@lv-x-software-house/x_view 1.2.4 → 1.2.5-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1665 -809
- package/dist/index.mjs +1672 -810
- package/package.json +52 -43
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import React25, {
|
|
2
|
+
import React25, {
|
|
3
|
+
useCallback as useCallback4,
|
|
4
|
+
useEffect as useEffect22,
|
|
5
|
+
useRef as useRef19,
|
|
6
|
+
useState as useState25,
|
|
7
|
+
useMemo as useMemo12
|
|
8
|
+
} from "react";
|
|
3
9
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
4
10
|
import { useSession } from "next-auth/react";
|
|
5
11
|
import CryptoJS from "crypto-js";
|
|
@@ -9890,7 +9896,6 @@ var GroupItem = ({
|
|
|
9890
9896
|
onPlayAncestry,
|
|
9891
9897
|
availableIds,
|
|
9892
9898
|
canEdit
|
|
9893
|
-
// [NOVO] Recebe permissão de edição
|
|
9894
9899
|
}) => {
|
|
9895
9900
|
const canIndent = index > 0;
|
|
9896
9901
|
const isPickingForThisGroup = pickingGroupId === group.id;
|
|
@@ -9905,107 +9910,126 @@ var GroupItem = ({
|
|
|
9905
9910
|
useEffect21(() => {
|
|
9906
9911
|
adjustHeight();
|
|
9907
9912
|
}, [group.text]);
|
|
9908
|
-
return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React24.createElement(
|
|
9913
|
+
return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React24.createElement(
|
|
9914
|
+
"div",
|
|
9915
|
+
{
|
|
9916
|
+
className: `
|
|
9909
9917
|
flex flex-col gap-2 py-2 px-3 transition-all duration-200
|
|
9910
9918
|
${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
|
|
9911
|
-
`
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
|
|
9915
|
-
className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
|
|
9916
|
-
rows: 1,
|
|
9917
|
-
style: {
|
|
9918
|
-
minHeight: "1.5rem",
|
|
9919
|
-
maxHeight: "250px"
|
|
9920
|
-
},
|
|
9921
|
-
placeholder: canEdit ? "Escreva sobre este grupo..." : "",
|
|
9922
|
-
value: group.text,
|
|
9923
|
-
readOnly: !canEdit,
|
|
9924
|
-
onChange: (e) => {
|
|
9925
|
-
if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
|
|
9926
|
-
}
|
|
9927
|
-
}
|
|
9928
|
-
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
|
|
9929
|
-
const isValid = availableIds.has(String(anc.ancestry_id));
|
|
9930
|
-
return /* @__PURE__ */ React24.createElement(
|
|
9931
|
-
"div",
|
|
9919
|
+
`
|
|
9920
|
+
},
|
|
9921
|
+
/* @__PURE__ */ React24.createElement(
|
|
9922
|
+
"textarea",
|
|
9932
9923
|
{
|
|
9933
|
-
|
|
9934
|
-
className: `
|
|
9924
|
+
ref: textareaRef,
|
|
9925
|
+
className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
|
|
9926
|
+
rows: 1,
|
|
9927
|
+
style: {
|
|
9928
|
+
minHeight: "1.5rem",
|
|
9929
|
+
maxHeight: "250px"
|
|
9930
|
+
},
|
|
9931
|
+
placeholder: canEdit ? "Escreva sobre este grupo..." : "",
|
|
9932
|
+
value: group.text,
|
|
9933
|
+
readOnly: !canEdit,
|
|
9934
|
+
onChange: (e) => {
|
|
9935
|
+
if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
|
|
9936
|
+
}
|
|
9937
|
+
}
|
|
9938
|
+
),
|
|
9939
|
+
group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
|
|
9940
|
+
const isValid = availableIds.has(String(anc.ancestry_id));
|
|
9941
|
+
return /* @__PURE__ */ React24.createElement(
|
|
9942
|
+
"div",
|
|
9943
|
+
{
|
|
9944
|
+
key: anc.ancestry_id,
|
|
9945
|
+
className: `
|
|
9935
9946
|
flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
|
|
9936
9947
|
${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
|
|
9937
9948
|
`,
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9949
|
+
title: isValid ? "" : "Esta ancestralidade foi removida ou n\xE3o existe mais."
|
|
9950
|
+
},
|
|
9951
|
+
isValid ? (
|
|
9952
|
+
// [MANTIDO] Botão Play visível para todos
|
|
9953
|
+
/* @__PURE__ */ React24.createElement(
|
|
9954
|
+
"button",
|
|
9955
|
+
{
|
|
9956
|
+
onClick: () => onPlayAncestry(anc.ancestry_id),
|
|
9957
|
+
className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
|
|
9958
|
+
title: "Renderizar no cen\xE1rio"
|
|
9959
|
+
},
|
|
9960
|
+
/* @__PURE__ */ React24.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
|
|
9961
|
+
)
|
|
9962
|
+
) : /* @__PURE__ */ React24.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React24.createElement(FiAlertTriangle, { size: 10 })),
|
|
9942
9963
|
/* @__PURE__ */ React24.createElement(
|
|
9964
|
+
"span",
|
|
9965
|
+
{
|
|
9966
|
+
className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}`
|
|
9967
|
+
},
|
|
9968
|
+
anc.name
|
|
9969
|
+
),
|
|
9970
|
+
canEdit && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
|
|
9971
|
+
"div",
|
|
9972
|
+
{
|
|
9973
|
+
className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}`
|
|
9974
|
+
}
|
|
9975
|
+
), /* @__PURE__ */ React24.createElement(
|
|
9943
9976
|
"button",
|
|
9944
9977
|
{
|
|
9945
|
-
onClick: () =>
|
|
9946
|
-
className: "text-
|
|
9947
|
-
title: "
|
|
9978
|
+
onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
|
|
9979
|
+
className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
|
|
9980
|
+
title: "Remover men\xE7\xE3o"
|
|
9948
9981
|
},
|
|
9949
|
-
/* @__PURE__ */ React24.createElement(
|
|
9950
|
-
)
|
|
9951
|
-
)
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
title: "Remover men\xE7\xE3o"
|
|
9959
|
-
},
|
|
9960
|
-
/* @__PURE__ */ React24.createElement(FiX7, { size: 12 })
|
|
9961
|
-
))
|
|
9962
|
-
);
|
|
9963
|
-
})), canEdit && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
9964
|
-
"button",
|
|
9965
|
-
{
|
|
9966
|
-
onClick: () => onRequestPickAncestry(group.id),
|
|
9967
|
-
className: `
|
|
9982
|
+
/* @__PURE__ */ React24.createElement(FiX7, { size: 12 })
|
|
9983
|
+
))
|
|
9984
|
+
);
|
|
9985
|
+
})),
|
|
9986
|
+
canEdit && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
9987
|
+
"button",
|
|
9988
|
+
{
|
|
9989
|
+
onClick: () => onRequestPickAncestry(group.id),
|
|
9990
|
+
className: `
|
|
9968
9991
|
flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors
|
|
9969
9992
|
${isPickingForThisGroup ? "text-indigo-300 animate-pulse" : "text-slate-500 hover:text-indigo-300 hover:bg-indigo-500/10"}
|
|
9970
9993
|
`,
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
9984
|
-
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
|
|
9988
|
-
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
9994
|
+
title: "Adicionar Ancestralidade a este grupo"
|
|
9995
|
+
},
|
|
9996
|
+
isPickingForThisGroup ? /* @__PURE__ */ React24.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React24.createElement(FiSearch4, { size: 12 }),
|
|
9997
|
+
isPickingForThisGroup ? "Selecionando..." : "Adicionar"
|
|
9998
|
+
), /* @__PURE__ */ React24.createElement(
|
|
9999
|
+
"button",
|
|
10000
|
+
{
|
|
10001
|
+
onClick: () => onAddSubgroup(group.id),
|
|
10002
|
+
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
10003
|
+
title: "Criar Subgrupo"
|
|
10004
|
+
},
|
|
10005
|
+
/* @__PURE__ */ React24.createElement(FiPlus9, { size: 14 })
|
|
10006
|
+
)), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
10007
|
+
"button",
|
|
10008
|
+
{
|
|
10009
|
+
onClick: () => onIndent(group.id),
|
|
10010
|
+
disabled: !canIndent,
|
|
10011
|
+
className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
|
|
10012
|
+
title: "Aninhar no grupo acima"
|
|
10013
|
+
},
|
|
10014
|
+
/* @__PURE__ */ React24.createElement(FiArrowRight, { size: 14 })
|
|
10015
|
+
), /* @__PURE__ */ React24.createElement(
|
|
10016
|
+
"button",
|
|
10017
|
+
{
|
|
10018
|
+
onClick: () => onOutdent(group.id),
|
|
10019
|
+
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
10020
|
+
title: "Desaninhar"
|
|
10021
|
+
},
|
|
10022
|
+
/* @__PURE__ */ React24.createElement(FiArrowLeft3, { size: 14 })
|
|
10023
|
+
), /* @__PURE__ */ React24.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement(
|
|
10024
|
+
"button",
|
|
10025
|
+
{
|
|
10026
|
+
onClick: () => onDelete(group.id),
|
|
10027
|
+
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
|
|
10028
|
+
title: "Remover Grupo"
|
|
10029
|
+
},
|
|
10030
|
+
/* @__PURE__ */ React24.createElement(FiTrash23, { size: 14 })
|
|
10031
|
+
)))
|
|
10032
|
+
), group.children && group.children.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React24.createElement(
|
|
10009
10033
|
GroupItem,
|
|
10010
10034
|
{
|
|
10011
10035
|
key: childGroup.id,
|
|
@@ -10214,7 +10238,9 @@ function AncestryBoard({
|
|
|
10214
10238
|
const addRecursive = (list) => {
|
|
10215
10239
|
return list.map((g) => {
|
|
10216
10240
|
if (g.id === pickingGroupId) {
|
|
10217
|
-
const exists = g.ancestries.some(
|
|
10241
|
+
const exists = g.ancestries.some(
|
|
10242
|
+
(a) => a.ancestry_id === ancestry.ancestry_id
|
|
10243
|
+
);
|
|
10218
10244
|
if (exists) return g;
|
|
10219
10245
|
return { ...g, ancestries: [...g.ancestries, ancestry] };
|
|
10220
10246
|
}
|
|
@@ -10225,12 +10251,16 @@ function AncestryBoard({
|
|
|
10225
10251
|
});
|
|
10226
10252
|
setPickingGroupId(null);
|
|
10227
10253
|
} else {
|
|
10228
|
-
const fullAncestry = availableAncestries.find(
|
|
10254
|
+
const fullAncestry = availableAncestries.find(
|
|
10255
|
+
(a) => a.ancestry_id === ancestry.ancestry_id
|
|
10256
|
+
) || ancestry;
|
|
10229
10257
|
onSelect(fullAncestry);
|
|
10230
10258
|
}
|
|
10231
10259
|
};
|
|
10232
10260
|
const handlePlayFromGroup = (ancestryId) => {
|
|
10233
|
-
const fullAncestry = availableAncestries.find(
|
|
10261
|
+
const fullAncestry = availableAncestries.find(
|
|
10262
|
+
(a) => a.ancestry_id === ancestryId
|
|
10263
|
+
);
|
|
10234
10264
|
if (fullAncestry && onSelect) {
|
|
10235
10265
|
onSelect(fullAncestry);
|
|
10236
10266
|
}
|
|
@@ -10240,7 +10270,12 @@ function AncestryBoard({
|
|
|
10240
10270
|
const removeRecursive = (list) => {
|
|
10241
10271
|
return list.map((g) => {
|
|
10242
10272
|
if (g.id === groupId) {
|
|
10243
|
-
return {
|
|
10273
|
+
return {
|
|
10274
|
+
...g,
|
|
10275
|
+
ancestries: g.ancestries.filter(
|
|
10276
|
+
(a) => a.ancestry_id !== ancestryId
|
|
10277
|
+
)
|
|
10278
|
+
};
|
|
10244
10279
|
}
|
|
10245
10280
|
return { ...g, children: removeRecursive(g.children) };
|
|
10246
10281
|
});
|
|
@@ -10261,7 +10296,13 @@ function AncestryBoard({
|
|
|
10261
10296
|
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",
|
|
10262
10297
|
onClick: (e) => e.stopPropagation()
|
|
10263
10298
|
},
|
|
10264
|
-
/* @__PURE__ */ React24.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React24.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React24.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
|
|
10299
|
+
/* @__PURE__ */ React24.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React24.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React24.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
|
|
10300
|
+
FiLoader5,
|
|
10301
|
+
{
|
|
10302
|
+
className: "animate-spin text-indigo-400",
|
|
10303
|
+
size: 12
|
|
10304
|
+
}
|
|
10305
|
+
), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ React24.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ React24.createElement(
|
|
10265
10306
|
"button",
|
|
10266
10307
|
{
|
|
10267
10308
|
onClick: handleAddRootGroup,
|
|
@@ -10277,57 +10318,75 @@ function AncestryBoard({
|
|
|
10277
10318
|
},
|
|
10278
10319
|
"\xD7"
|
|
10279
10320
|
))),
|
|
10280
|
-
/* @__PURE__ */ React24.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React24.createElement(
|
|
10321
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React24.createElement(
|
|
10322
|
+
"div",
|
|
10323
|
+
{
|
|
10324
|
+
className: `
|
|
10281
10325
|
flex flex-col border-r border-white/10 transition-all duration-300 flex-none
|
|
10282
10326
|
${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
|
|
10283
10327
|
min-w-[280px] max-w-[500px] bg-slate-900
|
|
10284
|
-
`
|
|
10285
|
-
|
|
10286
|
-
{
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10328
|
+
`
|
|
10329
|
+
},
|
|
10330
|
+
/* @__PURE__ */ React24.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React24.createElement("div", { className: "relative group" }, /* @__PURE__ */ React24.createElement(
|
|
10331
|
+
FiSearch4,
|
|
10332
|
+
{
|
|
10333
|
+
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"}`
|
|
10334
|
+
}
|
|
10335
|
+
), /* @__PURE__ */ React24.createElement(
|
|
10336
|
+
"input",
|
|
10337
|
+
{
|
|
10338
|
+
type: "text",
|
|
10339
|
+
placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar ancestralidade...",
|
|
10340
|
+
className: `
|
|
10290
10341
|
w-full rounded-md pl-9 pr-4 py-2 text-sm transition-all focus:outline-none focus:ring-1 focus:ring-indigo-500 border
|
|
10291
10342
|
${pickingGroupId ? "bg-indigo-950/30 border-indigo-500/30 text-white placeholder-indigo-300/50" : "bg-slate-950 border-white/10 text-slate-200 placeholder-slate-600"}
|
|
10292
10343
|
`,
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
|
|
10302
|
-
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10344
|
+
value: searchTerm,
|
|
10345
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
10346
|
+
autoFocus: !pickingGroupId
|
|
10347
|
+
}
|
|
10348
|
+
))),
|
|
10349
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
|
|
10350
|
+
const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
|
|
10351
|
+
const isPicking = !!pickingGroupId;
|
|
10352
|
+
return /* @__PURE__ */ React24.createElement(
|
|
10353
|
+
"div",
|
|
10354
|
+
{
|
|
10355
|
+
key: anc.ancestry_id,
|
|
10356
|
+
onClick: () => {
|
|
10357
|
+
if (isPicking) handleSelectAncestry(anc);
|
|
10358
|
+
},
|
|
10359
|
+
className: `
|
|
10308
10360
|
group relative flex items-start gap-3 p-3 text-left rounded-lg border transition-all duration-200
|
|
10309
10361
|
${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"}
|
|
10310
10362
|
`
|
|
10311
|
-
|
|
10312
|
-
|
|
10363
|
+
},
|
|
10364
|
+
/* @__PURE__ */ React24.createElement(
|
|
10365
|
+
"div",
|
|
10366
|
+
{
|
|
10367
|
+
className: `
|
|
10313
10368
|
mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
|
|
10314
10369
|
${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"}
|
|
10315
|
-
`
|
|
10316
|
-
/* @__PURE__ */ React24.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React24.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React24.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React24.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React24.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React24.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
|
|
10317
|
-
!isPicking && /* @__PURE__ */ React24.createElement(
|
|
10318
|
-
"button",
|
|
10319
|
-
{
|
|
10320
|
-
onClick: (e) => {
|
|
10321
|
-
e.stopPropagation();
|
|
10322
|
-
handleSelectAncestry(anc);
|
|
10370
|
+
`
|
|
10323
10371
|
},
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
},
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10372
|
+
isPicking ? /* @__PURE__ */ React24.createElement(FiPlus9, { size: 16 }) : /* @__PURE__ */ React24.createElement(FiLayers6, { size: 14 })
|
|
10373
|
+
),
|
|
10374
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React24.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React24.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React24.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React24.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React24.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
|
|
10375
|
+
!isPicking && /* @__PURE__ */ React24.createElement(
|
|
10376
|
+
"button",
|
|
10377
|
+
{
|
|
10378
|
+
onClick: (e) => {
|
|
10379
|
+
e.stopPropagation();
|
|
10380
|
+
handleSelectAncestry(anc);
|
|
10381
|
+
},
|
|
10382
|
+
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",
|
|
10383
|
+
title: "Renderizar Ancestralidade"
|
|
10384
|
+
},
|
|
10385
|
+
/* @__PURE__ */ React24.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React24.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
|
|
10386
|
+
)
|
|
10387
|
+
);
|
|
10388
|
+
}))
|
|
10389
|
+
), /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React24.createElement(FiLayers6, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React24.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React24.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React24.createElement(
|
|
10331
10390
|
GroupItem,
|
|
10332
10391
|
{
|
|
10333
10392
|
key: group.id,
|
|
@@ -10406,7 +10465,10 @@ var findNodePath3 = (tree, targetNodeId, currentPath = []) => {
|
|
|
10406
10465
|
}
|
|
10407
10466
|
if (tree.children) {
|
|
10408
10467
|
for (let i = 0; i < tree.children.length; i++) {
|
|
10409
|
-
const res = findNodePath3(tree.children[i], targetNodeId, [
|
|
10468
|
+
const res = findNodePath3(tree.children[i], targetNodeId, [
|
|
10469
|
+
...currentPath,
|
|
10470
|
+
i
|
|
10471
|
+
]);
|
|
10410
10472
|
if (res) return res;
|
|
10411
10473
|
}
|
|
10412
10474
|
}
|
|
@@ -10499,27 +10561,70 @@ function XViewScene({
|
|
|
10499
10561
|
const [userPermissionRole, setUserPermissionRole] = useState25(null);
|
|
10500
10562
|
const [isInitialized, setIsInitialized] = useState25(false);
|
|
10501
10563
|
const [sceneVersion, setSceneVersion] = useState25(0);
|
|
10502
|
-
const [contextMenu, setContextMenu] = useState25({
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10564
|
+
const [contextMenu, setContextMenu] = useState25({
|
|
10565
|
+
visible: false,
|
|
10566
|
+
x: 0,
|
|
10567
|
+
y: 0,
|
|
10568
|
+
nodeData: null
|
|
10569
|
+
});
|
|
10570
|
+
const [multiContextMenu, setMultiContextMenu] = useState25({
|
|
10571
|
+
visible: false,
|
|
10572
|
+
x: 0,
|
|
10573
|
+
y: 0,
|
|
10574
|
+
nodeIds: null
|
|
10575
|
+
});
|
|
10576
|
+
const [relationshipMenu, setRelationshipMenu] = useState25({
|
|
10577
|
+
visible: false,
|
|
10578
|
+
x: 0,
|
|
10579
|
+
y: 0,
|
|
10580
|
+
linkObject: null
|
|
10581
|
+
});
|
|
10582
|
+
const [creationMode, setCreationMode] = useState25({
|
|
10583
|
+
isActive: false,
|
|
10584
|
+
sourceNodeData: null
|
|
10585
|
+
});
|
|
10586
|
+
const [versionMode, setVersionMode] = useState25({
|
|
10587
|
+
isActive: false,
|
|
10588
|
+
sourceNodeData: null
|
|
10589
|
+
});
|
|
10507
10590
|
const [questMode, setQuestMode] = useState25({ isActive: false });
|
|
10508
10591
|
const [hasFocusedInitial, setHasFocusedInitial] = useState25(false);
|
|
10509
10592
|
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState25(false);
|
|
10510
|
-
const [ancestryMode, setAncestryMode] = useState25({
|
|
10593
|
+
const [ancestryMode, setAncestryMode] = useState25({
|
|
10594
|
+
isActive: false,
|
|
10595
|
+
tree: null,
|
|
10596
|
+
selectedParentId: null,
|
|
10597
|
+
isEditMode: false,
|
|
10598
|
+
currentAncestryId: null,
|
|
10599
|
+
ancestryName: "",
|
|
10600
|
+
ancestryDescription: "",
|
|
10601
|
+
ancestryDescriptionSections: [],
|
|
10602
|
+
isAddingNodes: false
|
|
10603
|
+
});
|
|
10511
10604
|
const [readingMode, setReadingMode] = useState25({
|
|
10512
10605
|
isActive: false,
|
|
10513
10606
|
ancestry: null,
|
|
10514
10607
|
branchStack: [],
|
|
10515
10608
|
autoAbstraction: false
|
|
10516
10609
|
});
|
|
10517
|
-
const [formPosition, setFormPosition] = useState25({
|
|
10610
|
+
const [formPosition, setFormPosition] = useState25({
|
|
10611
|
+
left: 16,
|
|
10612
|
+
top: 16,
|
|
10613
|
+
opacity: 0
|
|
10614
|
+
});
|
|
10518
10615
|
const [detailsNode, setDetailsNode] = useState25(null);
|
|
10519
10616
|
const [detailsLink, setDetailsLink] = useState25(null);
|
|
10520
10617
|
const [ancestryLinkDetails, setAncestryLinkDetails] = useState25(null);
|
|
10521
|
-
const [imageViewer, setImageViewer] = useState25({
|
|
10522
|
-
|
|
10618
|
+
const [imageViewer, setImageViewer] = useState25({
|
|
10619
|
+
visible: false,
|
|
10620
|
+
images: [],
|
|
10621
|
+
startIndex: 0
|
|
10622
|
+
});
|
|
10623
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState25({
|
|
10624
|
+
visible: false,
|
|
10625
|
+
data: null,
|
|
10626
|
+
path: null
|
|
10627
|
+
});
|
|
10523
10628
|
const [isImportModalOpen, setIsImportModalOpen] = useState25(false);
|
|
10524
10629
|
const [importSuccessMessage, setImportSuccessMessage] = useState25("");
|
|
10525
10630
|
const [highlightedNodeId, setHighlightedNodeId] = useState25(null);
|
|
@@ -10559,8 +10664,23 @@ function XViewScene({
|
|
|
10559
10664
|
ghostElements: { node: null, line: null, aura: null },
|
|
10560
10665
|
creation: { isActive: false, sourceNodeData: null },
|
|
10561
10666
|
connection: { isActive: false, sourceNodeData: null, line: null },
|
|
10562
|
-
relink: {
|
|
10563
|
-
|
|
10667
|
+
relink: {
|
|
10668
|
+
isActive: false,
|
|
10669
|
+
end: null,
|
|
10670
|
+
fixedNodeId: null,
|
|
10671
|
+
originalLine: null,
|
|
10672
|
+
line: null
|
|
10673
|
+
},
|
|
10674
|
+
ancestry: {
|
|
10675
|
+
isActive: false,
|
|
10676
|
+
tree: null,
|
|
10677
|
+
selectedParentId: null,
|
|
10678
|
+
isEditMode: false,
|
|
10679
|
+
currentAncestryId: null,
|
|
10680
|
+
ancestryName: "",
|
|
10681
|
+
ancestryDescription: "",
|
|
10682
|
+
isAddingNodes: false
|
|
10683
|
+
},
|
|
10564
10684
|
glowTexture: null,
|
|
10565
10685
|
nodeIdToParentFileMap: null,
|
|
10566
10686
|
maxAncestryRenderIndex: 0,
|
|
@@ -10569,7 +10689,11 @@ function XViewScene({
|
|
|
10569
10689
|
highlightedNodeId: null
|
|
10570
10690
|
});
|
|
10571
10691
|
const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
10572
|
-
const {
|
|
10692
|
+
const {
|
|
10693
|
+
width: readModeWidth,
|
|
10694
|
+
isResizing: isReadModeResizing,
|
|
10695
|
+
handlePointerDown: handleReadModeResize
|
|
10696
|
+
} = useResizablePanel({
|
|
10573
10697
|
initialWidth: 700,
|
|
10574
10698
|
minWidth: 320,
|
|
10575
10699
|
maxWidth: maxReadPanelW
|
|
@@ -10586,7 +10710,9 @@ function XViewScene({
|
|
|
10586
10710
|
for (const parentFileId in allParentData) {
|
|
10587
10711
|
if (allParentData.hasOwnProperty(parentFileId)) {
|
|
10588
10712
|
const parentFile = allParentData[parentFileId];
|
|
10589
|
-
const parentDbInfo = parentDbsArray.find(
|
|
10713
|
+
const parentDbInfo = parentDbsArray.find(
|
|
10714
|
+
(db) => String(db.db_id) === String(parentFileId)
|
|
10715
|
+
);
|
|
10590
10716
|
const ownerId2 = (parentDbInfo == null ? void 0 : parentDbInfo.owner_id) || null;
|
|
10591
10717
|
const datasetName = parentFile.dataset_name || `Dataset #${parentFileId.substring(0, 6)}`;
|
|
10592
10718
|
if (parentFile.nodes && ownerId2) {
|
|
@@ -10622,7 +10748,10 @@ function XViewScene({
|
|
|
10622
10748
|
if (files.length > 0 && get_single_parent_file && save_view_data) {
|
|
10623
10749
|
for (const file of files) {
|
|
10624
10750
|
try {
|
|
10625
|
-
const parentFileData = await get_single_parent_file(
|
|
10751
|
+
const parentFileData = await get_single_parent_file(
|
|
10752
|
+
file.id,
|
|
10753
|
+
session
|
|
10754
|
+
);
|
|
10626
10755
|
if (parentFileData.success && parentFileData.data) {
|
|
10627
10756
|
parentDataRef.current = {
|
|
10628
10757
|
...parentDataRef.current,
|
|
@@ -10633,7 +10762,11 @@ function XViewScene({
|
|
|
10633
10762
|
owner_id: session.user.id
|
|
10634
10763
|
};
|
|
10635
10764
|
updatedParentDbs.push(newParentDbObject);
|
|
10636
|
-
await add_new_parent_file_to_scene_at_firebase_action(
|
|
10765
|
+
await add_new_parent_file_to_scene_at_firebase_action(
|
|
10766
|
+
sceneConfigId,
|
|
10767
|
+
session,
|
|
10768
|
+
file.id
|
|
10769
|
+
);
|
|
10637
10770
|
importedIds.push(file.id);
|
|
10638
10771
|
successCount++;
|
|
10639
10772
|
}
|
|
@@ -10645,7 +10778,10 @@ function XViewScene({
|
|
|
10645
10778
|
if (viewToImport && get_ancestry_file) {
|
|
10646
10779
|
try {
|
|
10647
10780
|
const targetViewOwnerId = ((_b2 = (_a2 = viewToImport.members) == null ? void 0 : _a2.find((m) => m.permission === "owner")) == null ? void 0 : _b2.id) || session.user.id;
|
|
10648
|
-
const ancestryResponse = await get_ancestry_file(
|
|
10781
|
+
const ancestryResponse = await get_ancestry_file(
|
|
10782
|
+
viewToImport.id,
|
|
10783
|
+
targetViewOwnerId
|
|
10784
|
+
);
|
|
10649
10785
|
if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
|
|
10650
10786
|
const viewSpecificAncestries = ancestryResponse.data.filter(
|
|
10651
10787
|
(anc) => anc._source_file_id === viewToImport.id && !anc.is_private
|
|
@@ -10656,14 +10792,21 @@ function XViewScene({
|
|
|
10656
10792
|
_imported_from_view_owner_id: targetViewOwnerId,
|
|
10657
10793
|
_source_file_id: viewToImport.id,
|
|
10658
10794
|
_source_owner_id: targetViewOwnerId,
|
|
10659
|
-
_origin_db_ids: (viewToImport.selected_databases || []).map(
|
|
10795
|
+
_origin_db_ids: (viewToImport.selected_databases || []).map(
|
|
10796
|
+
(db) => db.db_id
|
|
10797
|
+
)
|
|
10660
10798
|
}));
|
|
10661
10799
|
const currentAncestries = ancestryDataRef.current || [];
|
|
10662
10800
|
const newAncestries = processedAncestries.filter(
|
|
10663
|
-
(newAnc) => !currentAncestries.some(
|
|
10801
|
+
(newAnc) => !currentAncestries.some(
|
|
10802
|
+
(curr) => String(curr.ancestry_id) === String(newAnc.ancestry_id)
|
|
10803
|
+
)
|
|
10664
10804
|
);
|
|
10665
10805
|
if (newAncestries.length > 0) {
|
|
10666
|
-
ancestryDataRef.current = [
|
|
10806
|
+
ancestryDataRef.current = [
|
|
10807
|
+
...currentAncestries,
|
|
10808
|
+
...newAncestries
|
|
10809
|
+
];
|
|
10667
10810
|
ancestriesWereImported = true;
|
|
10668
10811
|
}
|
|
10669
10812
|
}
|
|
@@ -10683,7 +10826,9 @@ function XViewScene({
|
|
|
10683
10826
|
if (ancestry_save_url) {
|
|
10684
10827
|
await save_view_data(ancestry_save_url, ancestryDataRef.current);
|
|
10685
10828
|
} else {
|
|
10686
|
-
console.error(
|
|
10829
|
+
console.error(
|
|
10830
|
+
"Erro: URL de salvamento de ancestralidade n\xE3o definida."
|
|
10831
|
+
);
|
|
10687
10832
|
}
|
|
10688
10833
|
}
|
|
10689
10834
|
setSceneVersion((v) => v + 1);
|
|
@@ -10691,113 +10836,136 @@ function XViewScene({
|
|
|
10691
10836
|
setImportSuccessMessage("Importa\xE7\xE3o conclu\xEDda com sucesso.");
|
|
10692
10837
|
setTimeout(() => setImportSuccessMessage(""), 5e3);
|
|
10693
10838
|
} else if (viewToImport && !ancestriesWereImported) {
|
|
10694
|
-
console.warn(
|
|
10839
|
+
console.warn(
|
|
10840
|
+
"Importa\xE7\xE3o finalizada, mas nenhum dado novo foi adicionado."
|
|
10841
|
+
);
|
|
10695
10842
|
}
|
|
10696
10843
|
},
|
|
10697
|
-
[
|
|
10844
|
+
[
|
|
10845
|
+
get_single_parent_file,
|
|
10846
|
+
get_ancestry_file,
|
|
10847
|
+
save_view_data,
|
|
10848
|
+
session,
|
|
10849
|
+
sceneSaveUrl,
|
|
10850
|
+
ancestry_save_url,
|
|
10851
|
+
sceneConfigId,
|
|
10852
|
+
add_new_parent_file_to_scene_at_firebase_action
|
|
10853
|
+
]
|
|
10698
10854
|
);
|
|
10699
10855
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
10700
10856
|
setImageViewer({ visible: true, images, startIndex });
|
|
10701
10857
|
};
|
|
10702
|
-
const tweenToTarget = useCallback4(
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10858
|
+
const tweenToTarget = useCallback4(
|
|
10859
|
+
(target, zoomFactor = 1, forcedDirection = null) => {
|
|
10860
|
+
const { camera, controls, tweenGroup } = stateRef.current;
|
|
10861
|
+
if (!camera || !controls || !tweenGroup) return;
|
|
10862
|
+
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
10863
|
+
const controlsTween = new Tween2(controls.target).to(targetPos, 1500).easing(Easing2.Cubic.Out);
|
|
10864
|
+
tweenGroup.add(controlsTween);
|
|
10865
|
+
controlsTween.start();
|
|
10866
|
+
let offset;
|
|
10867
|
+
if (forcedDirection) {
|
|
10868
|
+
offset = forcedDirection.clone().normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
|
|
10869
|
+
} else {
|
|
10870
|
+
offset = camera.position.clone().sub(controls.target).normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
|
|
10871
|
+
}
|
|
10872
|
+
const targetCameraPos = targetPos.clone().add(offset);
|
|
10873
|
+
const cameraTween = new Tween2(camera.position).to(targetCameraPos, 1500).easing(Easing2.Cubic.Out);
|
|
10874
|
+
tweenGroup.add(cameraTween);
|
|
10875
|
+
cameraTween.start();
|
|
10876
|
+
},
|
|
10877
|
+
[]
|
|
10878
|
+
);
|
|
10720
10879
|
const isFromUiOverlay = (event) => {
|
|
10721
10880
|
const t = event == null ? void 0 : event.target;
|
|
10722
10881
|
if (!t || typeof t.closest !== "function") return false;
|
|
10723
10882
|
return !!t.closest(".ui-overlay");
|
|
10724
10883
|
};
|
|
10725
|
-
const buildFullAncestryTree = useCallback4(
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
};
|
|
10736
|
-
}
|
|
10737
|
-
let nodeId = treeItem.node_id;
|
|
10738
|
-
if (!nodeId && treeItem.node) nodeId = treeItem.node.id;
|
|
10739
|
-
const fullNode = nodeMap.get(String(nodeId));
|
|
10740
|
-
const effectiveNode = fullNode || treeItem.node;
|
|
10741
|
-
let processedBranches = [];
|
|
10742
|
-
if (treeItem.parallel_branches && Array.isArray(treeItem.parallel_branches)) {
|
|
10743
|
-
processedBranches = treeItem.parallel_branches.map((branch) => {
|
|
10744
|
-
if (branch.linked_ancestry_id) {
|
|
10745
|
-
const linkedAncestry = ancestryMap.get(String(branch.linked_ancestry_id));
|
|
10746
|
-
if (linkedAncestry && linkedAncestry.tree) {
|
|
10747
|
-
const graftedTree = recursiveBuild(linkedAncestry.tree);
|
|
10748
|
-
return {
|
|
10749
|
-
...branch,
|
|
10750
|
-
name: linkedAncestry.name,
|
|
10751
|
-
description: linkedAncestry.description,
|
|
10752
|
-
description_sections: linkedAncestry.description_sections,
|
|
10753
|
-
tree: graftedTree,
|
|
10754
|
-
isLinked: true
|
|
10755
|
-
};
|
|
10756
|
-
}
|
|
10757
|
-
}
|
|
10884
|
+
const buildFullAncestryTree = useCallback4(
|
|
10885
|
+
(idTree, nodes, ancestries = []) => {
|
|
10886
|
+
if (!idTree) return null;
|
|
10887
|
+
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
10888
|
+
const ancestryMap = new Map(
|
|
10889
|
+
ancestries.map((a) => [String(a.ancestry_id), a])
|
|
10890
|
+
);
|
|
10891
|
+
const recursiveBuild = (treeItem) => {
|
|
10892
|
+
if (!treeItem) return null;
|
|
10893
|
+
if (treeItem.is_section) {
|
|
10758
10894
|
return {
|
|
10759
|
-
...
|
|
10760
|
-
|
|
10895
|
+
...treeItem,
|
|
10896
|
+
children: (treeItem.children || []).map(recursiveBuild).filter(Boolean)
|
|
10761
10897
|
};
|
|
10762
|
-
}
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
parallel_branches
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
return {
|
|
10786
|
-
...branch,
|
|
10787
|
-
name: linkedAncestry.name,
|
|
10788
|
-
description: linkedAncestry.description,
|
|
10789
|
-
description_sections: linkedAncestry.description_sections,
|
|
10790
|
-
tree: recursiveBuild(linkedAncestry.tree),
|
|
10791
|
-
isLinked: true
|
|
10792
|
-
};
|
|
10898
|
+
}
|
|
10899
|
+
let nodeId = treeItem.node_id;
|
|
10900
|
+
if (!nodeId && treeItem.node) nodeId = treeItem.node.id;
|
|
10901
|
+
const fullNode = nodeMap.get(String(nodeId));
|
|
10902
|
+
const effectiveNode = fullNode || treeItem.node;
|
|
10903
|
+
let processedBranches = [];
|
|
10904
|
+
if (treeItem.parallel_branches && Array.isArray(treeItem.parallel_branches)) {
|
|
10905
|
+
processedBranches = treeItem.parallel_branches.map((branch) => {
|
|
10906
|
+
if (branch.linked_ancestry_id) {
|
|
10907
|
+
const linkedAncestry = ancestryMap.get(
|
|
10908
|
+
String(branch.linked_ancestry_id)
|
|
10909
|
+
);
|
|
10910
|
+
if (linkedAncestry && linkedAncestry.tree) {
|
|
10911
|
+
const graftedTree = recursiveBuild(linkedAncestry.tree);
|
|
10912
|
+
return {
|
|
10913
|
+
...branch,
|
|
10914
|
+
name: linkedAncestry.name,
|
|
10915
|
+
description: linkedAncestry.description,
|
|
10916
|
+
description_sections: linkedAncestry.description_sections,
|
|
10917
|
+
tree: graftedTree,
|
|
10918
|
+
isLinked: true
|
|
10919
|
+
};
|
|
10920
|
+
}
|
|
10793
10921
|
}
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10922
|
+
return {
|
|
10923
|
+
...branch,
|
|
10924
|
+
tree: recursiveBuild(branch.tree)
|
|
10925
|
+
};
|
|
10926
|
+
});
|
|
10927
|
+
}
|
|
10928
|
+
return {
|
|
10929
|
+
...effectiveNode ? { node: effectiveNode } : { node: { id: nodeId, name: "Unknown" } },
|
|
10930
|
+
relationship: treeItem.relationship || {},
|
|
10931
|
+
children: (treeItem.children || []).map(recursiveBuild).filter(Boolean),
|
|
10932
|
+
parallel_branches: processedBranches
|
|
10933
|
+
};
|
|
10797
10934
|
};
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10935
|
+
let rootId = idTree.node_id;
|
|
10936
|
+
if (!rootId && idTree.node) rootId = idTree.node.id;
|
|
10937
|
+
if (rootId) {
|
|
10938
|
+
const rootNode = nodeMap.get(String(rootId));
|
|
10939
|
+
const effectiveRoot = rootNode || idTree.node;
|
|
10940
|
+
if (!effectiveRoot) return null;
|
|
10941
|
+
return {
|
|
10942
|
+
node: effectiveRoot,
|
|
10943
|
+
relationship: idTree.relationship || {},
|
|
10944
|
+
children: (idTree.children || []).map(recursiveBuild).filter(Boolean),
|
|
10945
|
+
parallel_branches: (idTree.parallel_branches || []).map((branch) => {
|
|
10946
|
+
if (branch.linked_ancestry_id) {
|
|
10947
|
+
const linkedAncestry = ancestryMap.get(
|
|
10948
|
+
String(branch.linked_ancestry_id)
|
|
10949
|
+
);
|
|
10950
|
+
if (linkedAncestry && linkedAncestry.tree) {
|
|
10951
|
+
return {
|
|
10952
|
+
...branch,
|
|
10953
|
+
name: linkedAncestry.name,
|
|
10954
|
+
description: linkedAncestry.description,
|
|
10955
|
+
description_sections: linkedAncestry.description_sections,
|
|
10956
|
+
tree: recursiveBuild(linkedAncestry.tree),
|
|
10957
|
+
isLinked: true
|
|
10958
|
+
};
|
|
10959
|
+
}
|
|
10960
|
+
}
|
|
10961
|
+
return { ...branch, tree: recursiveBuild(branch.tree) };
|
|
10962
|
+
})
|
|
10963
|
+
};
|
|
10964
|
+
}
|
|
10965
|
+
return recursiveBuild(idTree);
|
|
10966
|
+
},
|
|
10967
|
+
[]
|
|
10968
|
+
);
|
|
10801
10969
|
const handleActivateTimeline = useCallback4(() => {
|
|
10802
10970
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
10803
10971
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
@@ -10878,10 +11046,12 @@ function XViewScene({
|
|
|
10878
11046
|
if (timelineNodes.length === 0) return;
|
|
10879
11047
|
const sortedTimePoints = Array.from(allTimePoints).sort((a, b) => a - b);
|
|
10880
11048
|
const maxTimeIndex = sortedTimePoints.length - 1;
|
|
10881
|
-
const timeToYMap = new Map(
|
|
10882
|
-
time,
|
|
10883
|
-
|
|
10884
|
-
|
|
11049
|
+
const timeToYMap = new Map(
|
|
11050
|
+
sortedTimePoints.map((time, index) => [
|
|
11051
|
+
time,
|
|
11052
|
+
(index - maxTimeIndex) * TIMELINE_LAYER_SPACING_Y
|
|
11053
|
+
])
|
|
11054
|
+
);
|
|
10885
11055
|
timelineNodes.sort((a, b) => {
|
|
10886
11056
|
if (a.isUndated && b.isUndated) return 0;
|
|
10887
11057
|
if (a.isUndated) return 1;
|
|
@@ -10924,7 +11094,12 @@ function XViewScene({
|
|
|
10924
11094
|
if (type === "interval") {
|
|
10925
11095
|
const endY = timeToYMap.get(endDate.getTime());
|
|
10926
11096
|
if (endY > y) {
|
|
10927
|
-
const barGeometry = new THREE3.CylinderGeometry(
|
|
11097
|
+
const barGeometry = new THREE3.CylinderGeometry(
|
|
11098
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11099
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11100
|
+
1,
|
|
11101
|
+
16
|
|
11102
|
+
);
|
|
10928
11103
|
const barMaterial = new THREE3.MeshStandardMaterial({
|
|
10929
11104
|
color: TIMELINE_GOLD_COLOR,
|
|
10930
11105
|
emissive: 12092939,
|
|
@@ -10953,7 +11128,8 @@ function XViewScene({
|
|
|
10953
11128
|
}, []);
|
|
10954
11129
|
const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
|
|
10955
11130
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
10956
|
-
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
|
|
11131
|
+
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
|
|
11132
|
+
return;
|
|
10957
11133
|
versionMeshes.forEach((mesh) => {
|
|
10958
11134
|
const oldLabel = mesh.getObjectByName("timelineLabel");
|
|
10959
11135
|
if (oldLabel) {
|
|
@@ -10969,7 +11145,8 @@ function XViewScene({
|
|
|
10969
11145
|
}
|
|
10970
11146
|
if (mesh.userData.timelineEndLabel) {
|
|
10971
11147
|
timelineIntervalsGroup.remove(mesh.userData.timelineEndLabel);
|
|
10972
|
-
if (mesh.userData.timelineEndLabel.material.map)
|
|
11148
|
+
if (mesh.userData.timelineEndLabel.material.map)
|
|
11149
|
+
mesh.userData.timelineEndLabel.material.map.dispose();
|
|
10973
11150
|
mesh.userData.timelineEndLabel.material.dispose();
|
|
10974
11151
|
delete mesh.userData.timelineEndLabel;
|
|
10975
11152
|
}
|
|
@@ -11029,8 +11206,15 @@ function XViewScene({
|
|
|
11029
11206
|
});
|
|
11030
11207
|
if (timelineNodes.length === 0) return;
|
|
11031
11208
|
const sortedTimePoints = Array.from(allTimePoints).sort((a, b) => a - b);
|
|
11032
|
-
const timeToYMap = new Map(
|
|
11033
|
-
|
|
11209
|
+
const timeToYMap = new Map(
|
|
11210
|
+
sortedTimePoints.map((time, index) => [
|
|
11211
|
+
time,
|
|
11212
|
+
index * TIMELINE_LAYER_SPACING_Y
|
|
11213
|
+
])
|
|
11214
|
+
);
|
|
11215
|
+
timelineNodes.sort(
|
|
11216
|
+
(a, b) => a.startDate - b.startDate || a.endDate - b.endDate
|
|
11217
|
+
);
|
|
11034
11218
|
const baseX = sourceMesh.position.x + TIMELINE_NODE_SPACING_X;
|
|
11035
11219
|
const baseY = sourceMesh.position.y;
|
|
11036
11220
|
const maxNodeIndex = timelineNodes.length - 1;
|
|
@@ -11048,7 +11232,12 @@ function XViewScene({
|
|
|
11048
11232
|
if (type === "interval") {
|
|
11049
11233
|
const relativeEndY = timeToYMap.get(endDate.getTime()) - timeToYMap.get(startDate.getTime());
|
|
11050
11234
|
if (relativeEndY > 0) {
|
|
11051
|
-
const barGeometry = new THREE3.CylinderGeometry(
|
|
11235
|
+
const barGeometry = new THREE3.CylinderGeometry(
|
|
11236
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11237
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11238
|
+
1,
|
|
11239
|
+
16
|
|
11240
|
+
);
|
|
11052
11241
|
const barMaterial = new THREE3.MeshStandardMaterial({
|
|
11053
11242
|
color: TIMELINE_GOLD_COLOR,
|
|
11054
11243
|
emissive: 12092939,
|
|
@@ -11085,15 +11274,31 @@ function XViewScene({
|
|
|
11085
11274
|
try {
|
|
11086
11275
|
const typeStr = (viewParams == null ? void 0 : viewParams.type) || "";
|
|
11087
11276
|
const sceneType = typeStr.toLowerCase().includes("database") ? "database" : "view";
|
|
11088
|
-
const scenePromise = get_scene_view_data(
|
|
11277
|
+
const scenePromise = get_scene_view_data(
|
|
11278
|
+
configPath,
|
|
11279
|
+
ownerId2,
|
|
11280
|
+
typeStr,
|
|
11281
|
+
session,
|
|
11282
|
+
focusNodeId,
|
|
11283
|
+
focusAncestryId
|
|
11284
|
+
);
|
|
11089
11285
|
const boardPromise = get_ancestry_board_action && session ? get_ancestry_board_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
|
|
11090
|
-
const [sceneResponse, boardResponse] = await Promise.all([
|
|
11286
|
+
const [sceneResponse, boardResponse] = await Promise.all([
|
|
11287
|
+
scenePromise,
|
|
11288
|
+
boardPromise
|
|
11289
|
+
]);
|
|
11091
11290
|
if ((sceneResponse == null ? void 0 : sceneResponse.success) && ((_a2 = sceneResponse.data) == null ? void 0 : _a2.scene) && ((_b2 = sceneResponse.data) == null ? void 0 : _b2.parent)) {
|
|
11092
11291
|
if (focusNodeId) {
|
|
11093
|
-
let targetNode = sceneResponse.data.scene.nodes.find(
|
|
11292
|
+
let targetNode = sceneResponse.data.scene.nodes.find(
|
|
11293
|
+
(n) => String(n.id) === String(focusNodeId)
|
|
11294
|
+
);
|
|
11094
11295
|
if (!targetNode) {
|
|
11095
|
-
const allParentNodes = Object.values(
|
|
11096
|
-
|
|
11296
|
+
const allParentNodes = Object.values(
|
|
11297
|
+
sceneResponse.data.parent
|
|
11298
|
+
).flatMap((f) => f.nodes || []);
|
|
11299
|
+
targetNode = allParentNodes.find(
|
|
11300
|
+
(n) => String(n.id) === String(focusNodeId)
|
|
11301
|
+
);
|
|
11097
11302
|
}
|
|
11098
11303
|
if (targetNode) {
|
|
11099
11304
|
sceneResponse.data.scene.nodes = [targetNode];
|
|
@@ -11106,12 +11311,24 @@ function XViewScene({
|
|
|
11106
11311
|
sceneDataRef.current = sceneResponse.data.scene;
|
|
11107
11312
|
parentDataRef.current = sceneResponse.data.parent;
|
|
11108
11313
|
ancestryDataRef.current = sceneResponse.data.ancestry;
|
|
11109
|
-
console.log(
|
|
11110
|
-
|
|
11111
|
-
|
|
11314
|
+
console.log(
|
|
11315
|
+
"Console de sceneResponse.data.scene:",
|
|
11316
|
+
sceneResponse.data.scene
|
|
11317
|
+
);
|
|
11318
|
+
console.log(
|
|
11319
|
+
"Console de sceneResponse.data.parent:",
|
|
11320
|
+
sceneResponse.data.parent
|
|
11321
|
+
);
|
|
11322
|
+
console.log(
|
|
11323
|
+
"Console de sceneResponse.data.ancestry:",
|
|
11324
|
+
sceneResponse.data.ancestry
|
|
11325
|
+
);
|
|
11112
11326
|
setIsInitialized(true);
|
|
11113
11327
|
} else {
|
|
11114
|
-
console.error(
|
|
11328
|
+
console.error(
|
|
11329
|
+
"Falha ao buscar dados da cena:",
|
|
11330
|
+
(sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida."
|
|
11331
|
+
);
|
|
11115
11332
|
}
|
|
11116
11333
|
if (boardResponse == null ? void 0 : boardResponse.success) {
|
|
11117
11334
|
setAncestryBoardData(boardResponse.data);
|
|
@@ -11130,7 +11347,9 @@ function XViewScene({
|
|
|
11130
11347
|
console.error("Usu\xE1rio n\xE3o autenticado. Acesso negado.");
|
|
11131
11348
|
setIsLoading(false);
|
|
11132
11349
|
} else if (!sceneConfigId && status !== "loading") {
|
|
11133
|
-
console.warn(
|
|
11350
|
+
console.warn(
|
|
11351
|
+
"Nenhum par\xE2metro de cena encontrado na URL ou falha na decripta\xE7\xE3o."
|
|
11352
|
+
);
|
|
11134
11353
|
setIsLoading(false);
|
|
11135
11354
|
}
|
|
11136
11355
|
}, [
|
|
@@ -11151,33 +11370,46 @@ function XViewScene({
|
|
|
11151
11370
|
const objs = stateRef.current.nodeObjects || {};
|
|
11152
11371
|
return !!objs[key];
|
|
11153
11372
|
}, []);
|
|
11154
|
-
const addOrUpdateNodeMesh = useCallback4(
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
tweenGroup
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11373
|
+
const addOrUpdateNodeMesh = useCallback4(
|
|
11374
|
+
(nodeData, position, suppressVersionUpdate = false) => {
|
|
11375
|
+
const {
|
|
11376
|
+
graphGroup,
|
|
11377
|
+
nodeObjects,
|
|
11378
|
+
clickableNodes,
|
|
11379
|
+
glowTexture,
|
|
11380
|
+
tweenGroup
|
|
11381
|
+
} = stateRef.current;
|
|
11382
|
+
const nodeId = String(nodeData.id);
|
|
11383
|
+
if (nodeObjects[nodeId]) {
|
|
11384
|
+
const existingMesh = nodeObjects[nodeId];
|
|
11385
|
+
if (position) {
|
|
11386
|
+
const updateTween = new Tween2(existingMesh.position).to(position, 800).easing(Easing2.Cubic.Out);
|
|
11387
|
+
tweenGroup.add(updateTween);
|
|
11388
|
+
updateTween.start();
|
|
11389
|
+
}
|
|
11390
|
+
return existingMesh;
|
|
11391
|
+
}
|
|
11392
|
+
const mesh = createNodeMesh(
|
|
11393
|
+
nodeData,
|
|
11394
|
+
position || new THREE3.Vector3(),
|
|
11395
|
+
glowTexture
|
|
11396
|
+
);
|
|
11397
|
+
graphGroup.add(mesh);
|
|
11398
|
+
if (mesh.userData.labelObject) {
|
|
11399
|
+
if (mesh.userData.labelOffset) {
|
|
11400
|
+
mesh.userData.labelObject.position.copy(mesh.position).add(mesh.userData.labelOffset);
|
|
11401
|
+
}
|
|
11402
|
+
graphGroup.add(mesh.userData.labelObject);
|
|
11171
11403
|
}
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
}
|
|
11179
|
-
|
|
11180
|
-
|
|
11404
|
+
nodeObjects[nodeId] = mesh;
|
|
11405
|
+
clickableNodes.push(mesh);
|
|
11406
|
+
if (!suppressVersionUpdate) {
|
|
11407
|
+
setSceneVersion((v) => v + 1);
|
|
11408
|
+
}
|
|
11409
|
+
return mesh;
|
|
11410
|
+
},
|
|
11411
|
+
[]
|
|
11412
|
+
);
|
|
11181
11413
|
useEffect22(() => {
|
|
11182
11414
|
if (!isInitialized || !sceneDataRef.current) return;
|
|
11183
11415
|
const currentMount = mountRef.current;
|
|
@@ -11192,7 +11424,12 @@ function XViewScene({
|
|
|
11192
11424
|
const scene = new THREE3.Scene();
|
|
11193
11425
|
scene.background = new THREE3.Color(0);
|
|
11194
11426
|
stateRef.current.scene = scene;
|
|
11195
|
-
const camera = new THREE3.PerspectiveCamera(
|
|
11427
|
+
const camera = new THREE3.PerspectiveCamera(
|
|
11428
|
+
75,
|
|
11429
|
+
currentMount.clientWidth / currentMount.clientHeight,
|
|
11430
|
+
0.1,
|
|
11431
|
+
2e3
|
|
11432
|
+
);
|
|
11196
11433
|
camera.position.set(0, 60, 120);
|
|
11197
11434
|
stateRef.current.camera = camera;
|
|
11198
11435
|
const renderer = new THREE3.WebGLRenderer({ antialias: true });
|
|
@@ -11213,7 +11450,12 @@ function XViewScene({
|
|
|
11213
11450
|
directionalLight.position.set(50, 50, 50);
|
|
11214
11451
|
scene.add(directionalLight);
|
|
11215
11452
|
const renderScene = new RenderPass(scene, camera);
|
|
11216
|
-
const bloomPass = new UnrealBloomPass(
|
|
11453
|
+
const bloomPass = new UnrealBloomPass(
|
|
11454
|
+
new THREE3.Vector2(currentMount.clientWidth, currentMount.clientHeight),
|
|
11455
|
+
x_view_config.BLOOM_EFFECT.strength,
|
|
11456
|
+
x_view_config.BLOOM_EFFECT.radius,
|
|
11457
|
+
x_view_config.BLOOM_EFFECT.threshold
|
|
11458
|
+
);
|
|
11217
11459
|
const composer = new EffectComposer(renderer);
|
|
11218
11460
|
composer.addPass(renderScene);
|
|
11219
11461
|
composer.addPass(bloomPass);
|
|
@@ -11256,8 +11498,16 @@ function XViewScene({
|
|
|
11256
11498
|
const sourceNode = nodeObjects[String(linksArray[0].source)];
|
|
11257
11499
|
const targetNode = nodeObjects[String(linksArray[0].target)];
|
|
11258
11500
|
if (sourceNode && targetNode) {
|
|
11259
|
-
const resolution = new THREE3.Vector2(
|
|
11260
|
-
|
|
11501
|
+
const resolution = new THREE3.Vector2(
|
|
11502
|
+
currentMount.clientWidth,
|
|
11503
|
+
currentMount.clientHeight
|
|
11504
|
+
);
|
|
11505
|
+
const newLinks = createMultipleLinkLines(
|
|
11506
|
+
linksArray,
|
|
11507
|
+
sourceNode,
|
|
11508
|
+
targetNode,
|
|
11509
|
+
resolution
|
|
11510
|
+
);
|
|
11261
11511
|
newLinks.forEach((line, idx) => {
|
|
11262
11512
|
const meta = linksArray[idx];
|
|
11263
11513
|
if (meta) {
|
|
@@ -11298,7 +11548,10 @@ function XViewScene({
|
|
|
11298
11548
|
function tryPickNode() {
|
|
11299
11549
|
raycaster.setFromCamera(mouse, camera);
|
|
11300
11550
|
raycaster.layers.enable(GHOST_BLOOM_LAYER);
|
|
11301
|
-
const intersects = raycaster.intersectObjects(
|
|
11551
|
+
const intersects = raycaster.intersectObjects(
|
|
11552
|
+
stateRef.current.clickableNodes,
|
|
11553
|
+
false
|
|
11554
|
+
);
|
|
11302
11555
|
return intersects.length > 0 ? intersects[0].object : null;
|
|
11303
11556
|
}
|
|
11304
11557
|
function findClosestLinkToRay() {
|
|
@@ -11310,7 +11563,10 @@ function XViewScene({
|
|
|
11310
11563
|
x: (mouse.x * 0.5 + 0.5) * clientWidth,
|
|
11311
11564
|
y: (-mouse.y * 0.5 + 0.5) * clientHeight
|
|
11312
11565
|
};
|
|
11313
|
-
const allVisibleLinks = [
|
|
11566
|
+
const allVisibleLinks = [
|
|
11567
|
+
...stateRef.current.allLinks,
|
|
11568
|
+
...stateRef.current.ancestryLinks
|
|
11569
|
+
];
|
|
11314
11570
|
const THRESH = x_view_config.LINE_HOVER_THRESHOLD_PX + 4;
|
|
11315
11571
|
const tmpP1 = new THREE3.Vector3();
|
|
11316
11572
|
const tmpP2 = new THREE3.Vector3();
|
|
@@ -11325,19 +11581,35 @@ function XViewScene({
|
|
|
11325
11581
|
const up = new THREE3.Vector3(0, 1, 0);
|
|
11326
11582
|
const normal = new THREE3.Vector3().crossVectors(dir, up).normalize();
|
|
11327
11583
|
const controlPoint = mid.add(normal.multiplyScalar(curveOffset || 0));
|
|
11328
|
-
const curve = new THREE3.QuadraticBezierCurve3(
|
|
11584
|
+
const curve = new THREE3.QuadraticBezierCurve3(
|
|
11585
|
+
start,
|
|
11586
|
+
controlPoint,
|
|
11587
|
+
end
|
|
11588
|
+
);
|
|
11329
11589
|
const points = curve.getPoints(x_view_config.CURVE_SEGMENTS || 32);
|
|
11330
11590
|
for (let i = 0; i < points.length - 1; i++) {
|
|
11331
11591
|
tmpP1.copy(points[i]).project(camera);
|
|
11332
11592
|
tmpP2.copy(points[i + 1]).project(camera);
|
|
11333
|
-
const p1_px = {
|
|
11334
|
-
|
|
11593
|
+
const p1_px = {
|
|
11594
|
+
x: (tmpP1.x * 0.5 + 0.5) * clientWidth,
|
|
11595
|
+
y: (-tmpP1.y * 0.5 + 0.5) * clientHeight
|
|
11596
|
+
};
|
|
11597
|
+
const p2_px = {
|
|
11598
|
+
x: (tmpP2.x * 0.5 + 0.5) * clientWidth,
|
|
11599
|
+
y: (-tmpP2.y * 0.5 + 0.5) * clientHeight
|
|
11600
|
+
};
|
|
11335
11601
|
const L2 = (p2_px.x - p1_px.x) ** 2 + (p2_px.y - p1_px.y) ** 2;
|
|
11336
11602
|
if (L2 === 0) continue;
|
|
11337
11603
|
let t = ((mousePixels.x - p1_px.x) * (p2_px.x - p1_px.x) + (mousePixels.y - p1_px.y) * (p2_px.y - p1_px.y)) / L2;
|
|
11338
11604
|
t = Math.max(0, Math.min(1, t));
|
|
11339
|
-
const closestPoint = {
|
|
11340
|
-
|
|
11605
|
+
const closestPoint = {
|
|
11606
|
+
x: p1_px.x + t * (p2_px.x - p1_px.x),
|
|
11607
|
+
y: p1_px.y + t * (p2_px.y - p1_px.y)
|
|
11608
|
+
};
|
|
11609
|
+
const dist = Math.hypot(
|
|
11610
|
+
mousePixels.x - closestPoint.x,
|
|
11611
|
+
mousePixels.y - closestPoint.y
|
|
11612
|
+
);
|
|
11341
11613
|
if (dist < THRESH && dist < minDistance) {
|
|
11342
11614
|
minDistance = dist;
|
|
11343
11615
|
closestLink = link;
|
|
@@ -11346,14 +11618,26 @@ function XViewScene({
|
|
|
11346
11618
|
} else {
|
|
11347
11619
|
const p1 = new THREE3.Vector3().copy(sourceNode.position).project(camera);
|
|
11348
11620
|
const p2 = new THREE3.Vector3().copy(targetNode.position).project(camera);
|
|
11349
|
-
const p1_px = {
|
|
11350
|
-
|
|
11621
|
+
const p1_px = {
|
|
11622
|
+
x: (p1.x * 0.5 + 0.5) * clientWidth,
|
|
11623
|
+
y: (-p1.y * 0.5 + 0.5) * clientHeight
|
|
11624
|
+
};
|
|
11625
|
+
const p2_px = {
|
|
11626
|
+
x: (p2.x * 0.5 + 0.5) * clientWidth,
|
|
11627
|
+
y: (-p2.y * 0.5 + 0.5) * clientHeight
|
|
11628
|
+
};
|
|
11351
11629
|
const L2 = (p2_px.x - p1_px.x) ** 2 + (p2_px.y - p1_px.y) ** 2;
|
|
11352
11630
|
if (L2 === 0) return;
|
|
11353
11631
|
let t = ((mousePixels.x - p1_px.x) * (p2_px.x - p1_px.x) + (mousePixels.y - p1_px.y) * (p2_px.y - p1_px.y)) / L2;
|
|
11354
11632
|
t = Math.max(0, Math.min(1, t));
|
|
11355
|
-
const closestPoint = {
|
|
11356
|
-
|
|
11633
|
+
const closestPoint = {
|
|
11634
|
+
x: p1_px.x + t * (p2_px.x - p1_px.x),
|
|
11635
|
+
y: p1_px.y + t * (p2_px.y - p1_px.y)
|
|
11636
|
+
};
|
|
11637
|
+
const dist = Math.hypot(
|
|
11638
|
+
mousePixels.x - closestPoint.x,
|
|
11639
|
+
mousePixels.y - closestPoint.y
|
|
11640
|
+
);
|
|
11357
11641
|
if (dist < THRESH && dist < minDistance) {
|
|
11358
11642
|
minDistance = dist;
|
|
11359
11643
|
closestLink = link;
|
|
@@ -11388,7 +11672,11 @@ function XViewScene({
|
|
|
11388
11672
|
if (picked && !stateRef.current.ancestry.isActive) {
|
|
11389
11673
|
stateRef.current.controls.enabled = false;
|
|
11390
11674
|
}
|
|
11391
|
-
stateRef.current.pointerDown = {
|
|
11675
|
+
stateRef.current.pointerDown = {
|
|
11676
|
+
isDown: true,
|
|
11677
|
+
x: event.clientX,
|
|
11678
|
+
y: event.clientY
|
|
11679
|
+
};
|
|
11392
11680
|
stateRef.current.dragCandidate = picked;
|
|
11393
11681
|
}
|
|
11394
11682
|
function onPointerMove(event) {
|
|
@@ -11399,7 +11687,10 @@ function XViewScene({
|
|
|
11399
11687
|
const raycaster2 = new THREE3.Raycaster();
|
|
11400
11688
|
raycaster2.setFromCamera(mouse, camera);
|
|
11401
11689
|
camera.getWorldDirection(plane.normal);
|
|
11402
|
-
plane.setFromNormalAndCoplanarPoint(
|
|
11690
|
+
plane.setFromNormalAndCoplanarPoint(
|
|
11691
|
+
plane.normal,
|
|
11692
|
+
stateRef.current.draggedNode.position
|
|
11693
|
+
);
|
|
11403
11694
|
if (raycaster2.ray.intersectPlane(plane, intersectionPoint)) {
|
|
11404
11695
|
const draggedNode = stateRef.current.draggedNode;
|
|
11405
11696
|
draggedNode.position.copy(intersectionPoint);
|
|
@@ -11408,7 +11699,8 @@ function XViewScene({
|
|
|
11408
11699
|
}
|
|
11409
11700
|
if (stateRef.current.connection.isActive || stateRef.current.relink.isActive || stateRef.current.ancestry.isActive) {
|
|
11410
11701
|
const newHoveredNode2 = tryPickNode();
|
|
11411
|
-
if (stateRef.current.hoveredNode !== newHoveredNode2)
|
|
11702
|
+
if (stateRef.current.hoveredNode !== newHoveredNode2)
|
|
11703
|
+
stateRef.current.hoveredNode = newHoveredNode2;
|
|
11412
11704
|
if (currentMount) {
|
|
11413
11705
|
let fixedId = null;
|
|
11414
11706
|
if (stateRef.current.connection.isActive) {
|
|
@@ -11439,14 +11731,20 @@ function XViewScene({
|
|
|
11439
11731
|
stateRef.current.controls.enabled = false;
|
|
11440
11732
|
if (currentMount) currentMount.style.cursor = "grabbing";
|
|
11441
11733
|
camera.getWorldDirection(plane.normal);
|
|
11442
|
-
plane.setFromNormalAndCoplanarPoint(
|
|
11734
|
+
plane.setFromNormalAndCoplanarPoint(
|
|
11735
|
+
plane.normal,
|
|
11736
|
+
stateRef.current.draggedNode.position
|
|
11737
|
+
);
|
|
11443
11738
|
}
|
|
11444
11739
|
}
|
|
11445
11740
|
const newHoveredNode = tryPickNode();
|
|
11446
11741
|
const newHoveredLink = !newHoveredNode ? findClosestLinkToRay() : null;
|
|
11447
|
-
if (stateRef.current.hoveredNode !== newHoveredNode)
|
|
11448
|
-
|
|
11449
|
-
if (
|
|
11742
|
+
if (stateRef.current.hoveredNode !== newHoveredNode)
|
|
11743
|
+
stateRef.current.hoveredNode = newHoveredNode;
|
|
11744
|
+
if (stateRef.current.hoveredLink !== newHoveredLink)
|
|
11745
|
+
stateRef.current.hoveredLink = newHoveredLink;
|
|
11746
|
+
if (currentMount)
|
|
11747
|
+
currentMount.style.cursor = newHoveredNode || newHoveredLink ? "pointer" : "grab";
|
|
11450
11748
|
}
|
|
11451
11749
|
const isNodeInTree = (tree, nodeId) => {
|
|
11452
11750
|
if (!tree) return false;
|
|
@@ -11461,7 +11759,10 @@ function XViewScene({
|
|
|
11461
11759
|
const context = actionHandlerContext;
|
|
11462
11760
|
if (connection.isActive) {
|
|
11463
11761
|
if (hoveredNode && String(hoveredNode.userData.id) !== String(connection.sourceNodeData.id)) {
|
|
11464
|
-
await userActionHandlers.handleCompleteConnection(
|
|
11762
|
+
await userActionHandlers.handleCompleteConnection(
|
|
11763
|
+
context,
|
|
11764
|
+
hoveredNode.userData
|
|
11765
|
+
);
|
|
11465
11766
|
} else {
|
|
11466
11767
|
userActionHandlers.handleCancelConnection(context);
|
|
11467
11768
|
}
|
|
@@ -11469,7 +11770,10 @@ function XViewScene({
|
|
|
11469
11770
|
}
|
|
11470
11771
|
if (relink.isActive) {
|
|
11471
11772
|
if (hoveredNode && String(hoveredNode.userData.id) !== String(relink.fixedNodeId)) {
|
|
11472
|
-
await userActionHandlers.handleCompleteRelink(
|
|
11773
|
+
await userActionHandlers.handleCompleteRelink(
|
|
11774
|
+
context,
|
|
11775
|
+
hoveredNode.userData
|
|
11776
|
+
);
|
|
11473
11777
|
} else {
|
|
11474
11778
|
userActionHandlers.handleCancelRelink(context);
|
|
11475
11779
|
}
|
|
@@ -11487,7 +11791,9 @@ function XViewScene({
|
|
|
11487
11791
|
const clickedNodeId = String(clickedNode.userData.id);
|
|
11488
11792
|
const parentId = String(currentSelectedParent);
|
|
11489
11793
|
if (clickedNodeId === parentId) {
|
|
11490
|
-
alert(
|
|
11794
|
+
alert(
|
|
11795
|
+
"Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo."
|
|
11796
|
+
);
|
|
11491
11797
|
return;
|
|
11492
11798
|
}
|
|
11493
11799
|
const parentInfo = stateRef.current.nodeIdToParentFileMap.get(clickedNodeId);
|
|
@@ -11497,16 +11803,33 @@ function XViewScene({
|
|
|
11497
11803
|
const addChildToNode = (current, targetParentId, childNode) => {
|
|
11498
11804
|
const currentId = current.is_section ? current.id || current.section_id : String(current.node.id);
|
|
11499
11805
|
if (String(currentId) === String(targetParentId)) {
|
|
11500
|
-
const alreadyExists = current.children.some(
|
|
11806
|
+
const alreadyExists = current.children.some(
|
|
11807
|
+
(child) => !child.is_section && String(child.node.id) === String(childNode.id)
|
|
11808
|
+
);
|
|
11501
11809
|
if (alreadyExists) return current;
|
|
11502
|
-
return {
|
|
11810
|
+
return {
|
|
11811
|
+
...current,
|
|
11812
|
+
children: [
|
|
11813
|
+
...current.children,
|
|
11814
|
+
{ node: childNode, children: [], relationship: {} }
|
|
11815
|
+
]
|
|
11816
|
+
};
|
|
11503
11817
|
}
|
|
11504
|
-
return {
|
|
11818
|
+
return {
|
|
11819
|
+
...current,
|
|
11820
|
+
children: current.children.map(
|
|
11821
|
+
(c) => addChildToNode(c, targetParentId, childNode)
|
|
11822
|
+
)
|
|
11823
|
+
};
|
|
11505
11824
|
};
|
|
11506
11825
|
setAncestryMode((prev) => {
|
|
11507
11826
|
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
11508
11827
|
if (!prev[treeKey]) return prev;
|
|
11509
|
-
const newTree = addChildToNode(
|
|
11828
|
+
const newTree = addChildToNode(
|
|
11829
|
+
prev[treeKey],
|
|
11830
|
+
parentId,
|
|
11831
|
+
fullNodeData
|
|
11832
|
+
);
|
|
11510
11833
|
return { ...prev, [treeKey]: newTree };
|
|
11511
11834
|
});
|
|
11512
11835
|
}
|
|
@@ -11520,7 +11843,8 @@ function XViewScene({
|
|
|
11520
11843
|
stateRef.current.dragCandidate = null;
|
|
11521
11844
|
stateRef.current.pointerDown.isDown = false;
|
|
11522
11845
|
stateRef.current.controls.enabled = true;
|
|
11523
|
-
if (currentMount)
|
|
11846
|
+
if (currentMount)
|
|
11847
|
+
currentMount.style.cursor = stateRef.current.hoveredNode || stateRef.current.hoveredLink ? "pointer" : "grab";
|
|
11524
11848
|
return;
|
|
11525
11849
|
}
|
|
11526
11850
|
const dragDistance = Math.hypot(
|
|
@@ -11568,16 +11892,21 @@ function XViewScene({
|
|
|
11568
11892
|
}
|
|
11569
11893
|
function handleDoubleClick(event) {
|
|
11570
11894
|
if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
|
|
11571
|
-
if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11572
|
-
|
|
11895
|
+
if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11896
|
+
return;
|
|
11897
|
+
if (stateRef.current.hoveredNode)
|
|
11898
|
+
tweenToTarget(stateRef.current.hoveredNode);
|
|
11573
11899
|
}
|
|
11574
11900
|
function handleContextMenu(event) {
|
|
11575
11901
|
if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
|
|
11576
11902
|
if (isFromUiOverlay(event)) return;
|
|
11577
11903
|
event.preventDefault();
|
|
11578
|
-
if (stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11904
|
+
if (stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11905
|
+
return;
|
|
11579
11906
|
setMouseFromEvent(event);
|
|
11580
|
-
setContextMenu(
|
|
11907
|
+
setContextMenu(
|
|
11908
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
11909
|
+
);
|
|
11581
11910
|
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
11582
11911
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
11583
11912
|
const pickedNode = tryPickNode();
|
|
@@ -11608,7 +11937,12 @@ function XViewScene({
|
|
|
11608
11937
|
return;
|
|
11609
11938
|
}
|
|
11610
11939
|
stateRef.current.selectedNodes.clear();
|
|
11611
|
-
setRelationshipMenu({
|
|
11940
|
+
setRelationshipMenu({
|
|
11941
|
+
visible: true,
|
|
11942
|
+
x: event.clientX,
|
|
11943
|
+
y: event.clientY,
|
|
11944
|
+
linkObject: pickedLink
|
|
11945
|
+
});
|
|
11612
11946
|
return;
|
|
11613
11947
|
}
|
|
11614
11948
|
stateRef.current.selectedNodes.clear();
|
|
@@ -11640,7 +11974,10 @@ function XViewScene({
|
|
|
11640
11974
|
}
|
|
11641
11975
|
});
|
|
11642
11976
|
}
|
|
11643
|
-
const allRenderedLinks = [
|
|
11977
|
+
const allRenderedLinks = [
|
|
11978
|
+
...stateRef.current.allLinks,
|
|
11979
|
+
...stateRef.current.ancestryLinks
|
|
11980
|
+
];
|
|
11644
11981
|
allRenderedLinks.forEach((line) => {
|
|
11645
11982
|
const { sourceNode, targetNode, isCurved, curveOffset } = line.userData;
|
|
11646
11983
|
if (sourceNode && targetNode) {
|
|
@@ -11652,13 +11989,20 @@ function XViewScene({
|
|
|
11652
11989
|
const up = new THREE3.Vector3(0, 1, 0);
|
|
11653
11990
|
const normal = new THREE3.Vector3().crossVectors(dir, up).normalize();
|
|
11654
11991
|
const controlPoint = mid.add(normal.multiplyScalar(curveOffset));
|
|
11655
|
-
const curve = new THREE3.QuadraticBezierCurve3(
|
|
11992
|
+
const curve = new THREE3.QuadraticBezierCurve3(
|
|
11993
|
+
start,
|
|
11994
|
+
controlPoint,
|
|
11995
|
+
end
|
|
11996
|
+
);
|
|
11656
11997
|
const points = curve.getPoints(x_view_config.CURVE_SEGMENTS);
|
|
11657
11998
|
const positions = [];
|
|
11658
11999
|
points.forEach((p) => positions.push(p.x, p.y, p.z));
|
|
11659
12000
|
line.geometry.setPositions(positions);
|
|
11660
12001
|
} else {
|
|
11661
|
-
line.geometry.setPositions([
|
|
12002
|
+
line.geometry.setPositions([
|
|
12003
|
+
...sourceNode.position.toArray(),
|
|
12004
|
+
...targetNode.position.toArray()
|
|
12005
|
+
]);
|
|
11662
12006
|
}
|
|
11663
12007
|
}
|
|
11664
12008
|
});
|
|
@@ -11671,7 +12015,11 @@ function XViewScene({
|
|
|
11671
12015
|
const startPos = node.position;
|
|
11672
12016
|
const distance = startPos.distanceTo(endPos);
|
|
11673
12017
|
bar.scale.y = distance;
|
|
11674
|
-
const midpoint = new THREE3.Vector3().lerpVectors(
|
|
12018
|
+
const midpoint = new THREE3.Vector3().lerpVectors(
|
|
12019
|
+
startPos,
|
|
12020
|
+
endPos,
|
|
12021
|
+
0.5
|
|
12022
|
+
);
|
|
11675
12023
|
bar.position.copy(midpoint);
|
|
11676
12024
|
const direction = new THREE3.Vector3().subVectors(endPos, startPos).normalize();
|
|
11677
12025
|
const upVector = new THREE3.Vector3(0, 1, 0);
|
|
@@ -11682,7 +12030,11 @@ function XViewScene({
|
|
|
11682
12030
|
const { ghostElements, creation, connection, relink } = stateRef.current;
|
|
11683
12031
|
if (creation.isActive && ghostElements.node && ghostElements.line) {
|
|
11684
12032
|
const srcMesh = stateRef.current.nodeObjects[String(creation.sourceNodeData.id)];
|
|
11685
|
-
if (srcMesh)
|
|
12033
|
+
if (srcMesh)
|
|
12034
|
+
ghostElements.line.geometry.setPositions([
|
|
12035
|
+
...srcMesh.position.toArray(),
|
|
12036
|
+
...ghostElements.node.position.toArray()
|
|
12037
|
+
]);
|
|
11686
12038
|
}
|
|
11687
12039
|
if (connection.isActive && connection.line) {
|
|
11688
12040
|
const srcMesh = stateRef.current.nodeObjects[String(connection.sourceNodeData.id)];
|
|
@@ -11691,7 +12043,11 @@ function XViewScene({
|
|
|
11691
12043
|
raycaster2.setFromCamera(mouse, camera);
|
|
11692
12044
|
camera.getWorldDirection(plane.normal);
|
|
11693
12045
|
plane.setFromNormalAndCoplanarPoint(plane.normal, srcMesh.position);
|
|
11694
|
-
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12046
|
+
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12047
|
+
connection.line.geometry.setPositions([
|
|
12048
|
+
...srcMesh.position.toArray(),
|
|
12049
|
+
...intersectionPoint.toArray()
|
|
12050
|
+
]);
|
|
11695
12051
|
}
|
|
11696
12052
|
}
|
|
11697
12053
|
if (relink.isActive && relink.line) {
|
|
@@ -11701,7 +12057,11 @@ function XViewScene({
|
|
|
11701
12057
|
raycaster2.setFromCamera(mouse, camera);
|
|
11702
12058
|
camera.getWorldDirection(plane.normal);
|
|
11703
12059
|
plane.setFromNormalAndCoplanarPoint(plane.normal, fixedMesh.position);
|
|
11704
|
-
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12060
|
+
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12061
|
+
relink.line.geometry.setPositions([
|
|
12062
|
+
...fixedMesh.position.toArray(),
|
|
12063
|
+
...intersectionPoint.toArray()
|
|
12064
|
+
]);
|
|
11705
12065
|
}
|
|
11706
12066
|
}
|
|
11707
12067
|
Object.values(stateRef.current.nodeObjects).forEach((node) => {
|
|
@@ -11745,11 +12105,18 @@ function XViewScene({
|
|
|
11745
12105
|
renderer.setSize(clientWidth, clientHeight);
|
|
11746
12106
|
composer.setSize(clientWidth, clientHeight);
|
|
11747
12107
|
const resVec = new THREE3.Vector2(clientWidth, clientHeight);
|
|
11748
|
-
stateRef.current.allLinks.forEach(
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
12108
|
+
stateRef.current.allLinks.forEach(
|
|
12109
|
+
(line) => line.material.resolution.copy(resVec)
|
|
12110
|
+
);
|
|
12111
|
+
stateRef.current.ancestryLinks.forEach(
|
|
12112
|
+
(line) => line.material.resolution.copy(resVec)
|
|
12113
|
+
);
|
|
12114
|
+
if (stateRef.current.ghostElements.line)
|
|
12115
|
+
stateRef.current.ghostElements.line.material.resolution.copy(resVec);
|
|
12116
|
+
if (stateRef.current.connection.line)
|
|
12117
|
+
stateRef.current.connection.line.material.resolution.copy(resVec);
|
|
12118
|
+
if (stateRef.current.relink.line)
|
|
12119
|
+
stateRef.current.relink.line.material.resolution.copy(resVec);
|
|
11753
12120
|
}
|
|
11754
12121
|
window.addEventListener("resize", handleResize);
|
|
11755
12122
|
return () => {
|
|
@@ -11769,14 +12136,16 @@ function XViewScene({
|
|
|
11769
12136
|
ancestryGroup.traverse((obj) => {
|
|
11770
12137
|
if (obj.geometry) obj.geometry.dispose();
|
|
11771
12138
|
if (obj.material) {
|
|
11772
|
-
if (Array.isArray(obj.material))
|
|
12139
|
+
if (Array.isArray(obj.material))
|
|
12140
|
+
obj.material.forEach((m) => m.dispose());
|
|
11773
12141
|
else obj.material.dispose();
|
|
11774
12142
|
}
|
|
11775
12143
|
});
|
|
11776
12144
|
graphGroup.traverse((obj) => {
|
|
11777
12145
|
if (obj.geometry) obj.geometry.dispose();
|
|
11778
12146
|
if (obj.material) {
|
|
11779
|
-
if (Array.isArray(obj.material))
|
|
12147
|
+
if (Array.isArray(obj.material))
|
|
12148
|
+
obj.material.forEach((m) => m.dispose());
|
|
11780
12149
|
else obj.material.dispose();
|
|
11781
12150
|
}
|
|
11782
12151
|
});
|
|
@@ -11787,9 +12156,22 @@ function XViewScene({
|
|
|
11787
12156
|
currentMount.removeChild(renderer.domElement);
|
|
11788
12157
|
}
|
|
11789
12158
|
};
|
|
11790
|
-
}, [
|
|
11791
|
-
|
|
11792
|
-
|
|
12159
|
+
}, [
|
|
12160
|
+
isInitialized,
|
|
12161
|
+
tweenToTarget,
|
|
12162
|
+
dbSaveUrl,
|
|
12163
|
+
isNodeInView,
|
|
12164
|
+
addOrUpdateNodeMesh,
|
|
12165
|
+
handleActivateTimeline,
|
|
12166
|
+
get_scene_view_data,
|
|
12167
|
+
save_view_data
|
|
12168
|
+
]);
|
|
12169
|
+
const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
|
|
12170
|
+
const {
|
|
12171
|
+
node: ghostNode,
|
|
12172
|
+
line: ghostLine,
|
|
12173
|
+
aura: ghostAura
|
|
12174
|
+
} = stateRef.current.ghostElements;
|
|
11793
12175
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
11794
12176
|
if (!ghostNode || !graphGroup) return;
|
|
11795
12177
|
const currentData = {
|
|
@@ -11800,13 +12182,15 @@ function XViewScene({
|
|
|
11800
12182
|
const position = ghostNode.position.clone();
|
|
11801
12183
|
if (ghostNode.userData.labelObject) {
|
|
11802
12184
|
graphGroup.remove(ghostNode.userData.labelObject);
|
|
11803
|
-
if (ghostNode.userData.labelObject.material.map)
|
|
12185
|
+
if (ghostNode.userData.labelObject.material.map)
|
|
12186
|
+
ghostNode.userData.labelObject.material.map.dispose();
|
|
11804
12187
|
ghostNode.userData.labelObject.material.dispose();
|
|
11805
12188
|
}
|
|
11806
12189
|
graphGroup.remove(ghostNode);
|
|
11807
12190
|
if (ghostNode.geometry) ghostNode.geometry.dispose();
|
|
11808
12191
|
if (ghostNode.material) {
|
|
11809
|
-
if (Array.isArray(ghostNode.material))
|
|
12192
|
+
if (Array.isArray(ghostNode.material))
|
|
12193
|
+
ghostNode.material.forEach((m) => m.dispose());
|
|
11810
12194
|
else ghostNode.material.dispose();
|
|
11811
12195
|
}
|
|
11812
12196
|
const newGhostNode = createNodeMesh(currentData, position, glowTexture);
|
|
@@ -11851,28 +12235,31 @@ function XViewScene({
|
|
|
11851
12235
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
11852
12236
|
}
|
|
11853
12237
|
}, []);
|
|
11854
|
-
const handleDetailNodeIntensityChange = useCallback4(
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
borderMesh.material
|
|
12238
|
+
const handleDetailNodeIntensityChange = useCallback4(
|
|
12239
|
+
(nodeId, newIntensity) => {
|
|
12240
|
+
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
12241
|
+
if (!mesh) return;
|
|
12242
|
+
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
12243
|
+
mesh.userData.intensity = newIntensity;
|
|
12244
|
+
mesh.userData._baseEmissiveIntensity = adjustedIntensity;
|
|
12245
|
+
const isImageNode = mesh.userData.useImageAsTexture === true;
|
|
12246
|
+
if (isImageNode) {
|
|
12247
|
+
const borderMesh = mesh.getObjectByName("borderRing");
|
|
12248
|
+
if (borderMesh && borderMesh.material) {
|
|
12249
|
+
borderMesh.material.emissiveIntensity = adjustedIntensity;
|
|
12250
|
+
}
|
|
12251
|
+
} else {
|
|
12252
|
+
if (mesh.material) {
|
|
12253
|
+
mesh.material.emissiveIntensity = adjustedIntensity;
|
|
12254
|
+
}
|
|
11865
12255
|
}
|
|
11866
|
-
|
|
11867
|
-
if (
|
|
11868
|
-
|
|
12256
|
+
const aura = mesh.getObjectByName("aura");
|
|
12257
|
+
if (aura && aura.material) {
|
|
12258
|
+
aura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
11869
12259
|
}
|
|
11870
|
-
}
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
aura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
11874
|
-
}
|
|
11875
|
-
}, []);
|
|
12260
|
+
},
|
|
12261
|
+
[]
|
|
12262
|
+
);
|
|
11876
12263
|
const handleGhostNodeColorChange = (newColor) => {
|
|
11877
12264
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
11878
12265
|
if (!ghostNode) return;
|
|
@@ -11983,7 +12370,9 @@ function XViewScene({
|
|
|
11983
12370
|
mesh.userData.size = newSize;
|
|
11984
12371
|
};
|
|
11985
12372
|
const handleStartAncestryCreation = (nodeData) => {
|
|
11986
|
-
setContextMenu(
|
|
12373
|
+
setContextMenu(
|
|
12374
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
12375
|
+
);
|
|
11987
12376
|
stateRef.current.maxAncestryRenderIndex = 0;
|
|
11988
12377
|
setAncestryMode({
|
|
11989
12378
|
isActive: true,
|
|
@@ -12008,9 +12397,12 @@ function XViewScene({
|
|
|
12008
12397
|
const newTreeStr = JSON.stringify(newTree);
|
|
12009
12398
|
let metaChanged = false;
|
|
12010
12399
|
if (extraData) {
|
|
12011
|
-
if (extraData.ancestryName !== void 0 && extraData.ancestryName !== prev.ancestryName)
|
|
12012
|
-
|
|
12013
|
-
if (extraData.
|
|
12400
|
+
if (extraData.ancestryName !== void 0 && extraData.ancestryName !== prev.ancestryName)
|
|
12401
|
+
metaChanged = true;
|
|
12402
|
+
if (extraData.ancestryDescription !== void 0 && extraData.ancestryDescription !== prev.ancestryDescription)
|
|
12403
|
+
metaChanged = true;
|
|
12404
|
+
if (extraData.ancestryDescriptionSections !== void 0 && JSON.stringify(extraData.ancestryDescriptionSections) !== JSON.stringify(prev.ancestryDescriptionSections))
|
|
12405
|
+
metaChanged = true;
|
|
12014
12406
|
}
|
|
12015
12407
|
if (prevTreeStr === newTreeStr && !metaChanged) {
|
|
12016
12408
|
return prev;
|
|
@@ -12088,13 +12480,15 @@ function XViewScene({
|
|
|
12088
12480
|
if (ghostElements.node && graphGroup) {
|
|
12089
12481
|
if (ghostElements.node.userData.labelObject) {
|
|
12090
12482
|
graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
12091
|
-
if (ghostElements.node.userData.labelObject.material.map)
|
|
12483
|
+
if (ghostElements.node.userData.labelObject.material.map)
|
|
12484
|
+
ghostElements.node.userData.labelObject.material.map.dispose();
|
|
12092
12485
|
ghostElements.node.userData.labelObject.material.dispose();
|
|
12093
12486
|
}
|
|
12094
12487
|
graphGroup.remove(ghostElements.node);
|
|
12095
12488
|
ghostElements.node.traverse((child) => {
|
|
12096
12489
|
if (child.material) {
|
|
12097
|
-
if (Array.isArray(child.material))
|
|
12490
|
+
if (Array.isArray(child.material))
|
|
12491
|
+
child.material.forEach((m) => m.dispose());
|
|
12098
12492
|
else child.material.dispose();
|
|
12099
12493
|
}
|
|
12100
12494
|
if (child.geometry) child.geometry.dispose();
|
|
@@ -12104,7 +12498,17 @@ function XViewScene({
|
|
|
12104
12498
|
setQuestMode({ isActive: false });
|
|
12105
12499
|
}, []);
|
|
12106
12500
|
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
12107
|
-
const {
|
|
12501
|
+
const {
|
|
12502
|
+
graphDataRef,
|
|
12503
|
+
sceneDataRef: sceneDataRef2,
|
|
12504
|
+
stateRef: stateRef2,
|
|
12505
|
+
setters,
|
|
12506
|
+
actions,
|
|
12507
|
+
sceneSaveUrl: sceneSaveUrl2,
|
|
12508
|
+
viewType,
|
|
12509
|
+
sceneConfigId: sceneConfigId2,
|
|
12510
|
+
ownerId: ownerId2
|
|
12511
|
+
} = context;
|
|
12108
12512
|
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
12109
12513
|
const currentCounter = sceneDataRef2.current.quest_counter || 1;
|
|
12110
12514
|
const newNode = {
|
|
@@ -12137,7 +12541,8 @@ function XViewScene({
|
|
|
12137
12541
|
const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
|
|
12138
12542
|
const { graphGroup, ghostElements } = stateRef2.current;
|
|
12139
12543
|
if (ghostElements.node && graphGroup) {
|
|
12140
|
-
if (ghostElements.node.userData.labelObject)
|
|
12544
|
+
if (ghostElements.node.userData.labelObject)
|
|
12545
|
+
graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
12141
12546
|
graphGroup.remove(ghostElements.node);
|
|
12142
12547
|
}
|
|
12143
12548
|
stateRef2.current.ghostElements = { node: null, line: null, aura: null };
|
|
@@ -12151,14 +12556,33 @@ function XViewScene({
|
|
|
12151
12556
|
}
|
|
12152
12557
|
};
|
|
12153
12558
|
userActionHandlers.handleCompleteConnection = async (context, targetNodeData) => {
|
|
12154
|
-
const {
|
|
12559
|
+
const {
|
|
12560
|
+
stateRef: stateRef2,
|
|
12561
|
+
graphDataRef,
|
|
12562
|
+
sceneDataRef: sceneDataRef2,
|
|
12563
|
+
sceneConfigId: sceneConfigId2,
|
|
12564
|
+
sceneSaveUrl: sceneSaveUrl2,
|
|
12565
|
+
ownerId: ownerId2
|
|
12566
|
+
} = context;
|
|
12155
12567
|
const { sourceNodeData } = stateRef2.current.connection;
|
|
12156
12568
|
if (!graphDataRef.current || !sceneDataRef2.current || !sourceNodeData || !targetNodeData) {
|
|
12157
12569
|
userActionHandlers.handleCancelConnection(context);
|
|
12158
12570
|
return;
|
|
12159
12571
|
}
|
|
12160
|
-
const sourceParentInfo = getParentFileInfoForNode(
|
|
12161
|
-
|
|
12572
|
+
const sourceParentInfo = getParentFileInfoForNode(
|
|
12573
|
+
graphDataRef.current,
|
|
12574
|
+
sceneDataRef2.current,
|
|
12575
|
+
sourceNodeData.id,
|
|
12576
|
+
sceneConfigId2,
|
|
12577
|
+
ownerId2
|
|
12578
|
+
);
|
|
12579
|
+
const targetParentInfo = getParentFileInfoForNode(
|
|
12580
|
+
graphDataRef.current,
|
|
12581
|
+
sceneDataRef2.current,
|
|
12582
|
+
targetNodeData.id,
|
|
12583
|
+
sceneConfigId2,
|
|
12584
|
+
ownerId2
|
|
12585
|
+
);
|
|
12162
12586
|
let parentInfoToSave = sourceParentInfo;
|
|
12163
12587
|
const isSourceQuest = sourceParentInfo.parentFileId === sceneConfigId2;
|
|
12164
12588
|
const isTargetQuest = targetParentInfo.parentFileId === sceneConfigId2;
|
|
@@ -12184,10 +12608,15 @@ function XViewScene({
|
|
|
12184
12608
|
};
|
|
12185
12609
|
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
12186
12610
|
} else {
|
|
12187
|
-
const specificParentData = JSON.parse(
|
|
12611
|
+
const specificParentData = JSON.parse(
|
|
12612
|
+
JSON.stringify(graphDataRef.current[parentFileIdToSave])
|
|
12613
|
+
);
|
|
12188
12614
|
specificParentData.links.push(newLink);
|
|
12189
12615
|
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
12190
|
-
await context.actions.save_view_data(
|
|
12616
|
+
await context.actions.save_view_data(
|
|
12617
|
+
filenameForSpecificParent,
|
|
12618
|
+
specificParentData
|
|
12619
|
+
);
|
|
12191
12620
|
graphDataRef.current[parentFileIdToSave] = specificParentData;
|
|
12192
12621
|
}
|
|
12193
12622
|
addNewLinkToScene(stateRef2.current, newLink);
|
|
@@ -12199,7 +12628,9 @@ function XViewScene({
|
|
|
12199
12628
|
};
|
|
12200
12629
|
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
12201
12630
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
12202
|
-
const renderIndex = renderedAncestries.findIndex(
|
|
12631
|
+
const renderIndex = renderedAncestries.findIndex(
|
|
12632
|
+
(a) => String(a.id) === String(ancestryId)
|
|
12633
|
+
);
|
|
12203
12634
|
if (renderIndex !== -1) {
|
|
12204
12635
|
const toRemove = renderedAncestries[renderIndex];
|
|
12205
12636
|
toRemove.lines.forEach((line) => {
|
|
@@ -12208,12 +12639,16 @@ function XViewScene({
|
|
|
12208
12639
|
if (line.material) line.material.dispose();
|
|
12209
12640
|
});
|
|
12210
12641
|
renderedAncestries.splice(renderIndex, 1);
|
|
12211
|
-
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
12642
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
12643
|
+
(a) => a.lines
|
|
12644
|
+
);
|
|
12212
12645
|
}
|
|
12213
12646
|
}, []);
|
|
12214
12647
|
const handleRenderAncestry = useCallback4(
|
|
12215
12648
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
12216
|
-
setContextMenu(
|
|
12649
|
+
setContextMenu(
|
|
12650
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
12651
|
+
);
|
|
12217
12652
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
12218
12653
|
return;
|
|
12219
12654
|
}
|
|
@@ -12240,14 +12675,16 @@ function XViewScene({
|
|
|
12240
12675
|
if (numId !== void 0 && normalizedAllowedIds.has(numId)) return true;
|
|
12241
12676
|
if (strId && normalizedAllowedIds.has(strId)) return true;
|
|
12242
12677
|
if (strSecId && normalizedAllowedIds.has(strSecId)) return true;
|
|
12243
|
-
if (numId !== void 0 && normalizedAllowedIds.has(String(numId)))
|
|
12678
|
+
if (numId !== void 0 && normalizedAllowedIds.has(String(numId)))
|
|
12679
|
+
return true;
|
|
12244
12680
|
return false;
|
|
12245
12681
|
};
|
|
12246
12682
|
const checkIsActive = (section, targetId) => {
|
|
12247
12683
|
if (targetId === null || targetId === void 0) return false;
|
|
12248
12684
|
const sTarget = String(targetId);
|
|
12249
12685
|
if (section.id && String(section.id) === sTarget) return true;
|
|
12250
|
-
if (section.section_id && String(section.section_id) === sTarget)
|
|
12686
|
+
if (section.section_id && String(section.section_id) === sTarget)
|
|
12687
|
+
return true;
|
|
12251
12688
|
if (section.section_numeric_id !== void 0) {
|
|
12252
12689
|
if (String(section.section_numeric_id) === sTarget) return true;
|
|
12253
12690
|
}
|
|
@@ -12263,7 +12700,9 @@ function XViewScene({
|
|
|
12263
12700
|
traverse(sectionTree);
|
|
12264
12701
|
return ids;
|
|
12265
12702
|
};
|
|
12266
|
-
const existingIndex = renderedAncestries.findIndex(
|
|
12703
|
+
const existingIndex = renderedAncestries.findIndex(
|
|
12704
|
+
(a) => String(a.id) === String(ancestryObject.ancestry_id)
|
|
12705
|
+
);
|
|
12267
12706
|
let skipGeneration = false;
|
|
12268
12707
|
let ancestryEntry = null;
|
|
12269
12708
|
if (existingIndex !== -1) {
|
|
@@ -12318,9 +12757,15 @@ function XViewScene({
|
|
|
12318
12757
|
if (line.material) line.material.dispose();
|
|
12319
12758
|
});
|
|
12320
12759
|
}
|
|
12321
|
-
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
12760
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
12761
|
+
(fileData) => fileData.nodes
|
|
12762
|
+
);
|
|
12322
12763
|
const allAncestries = ancestryDataRef.current || [];
|
|
12323
|
-
const fullTree = buildFullAncestryTree(
|
|
12764
|
+
const fullTree = buildFullAncestryTree(
|
|
12765
|
+
ancestryObject.tree,
|
|
12766
|
+
allParentNodes,
|
|
12767
|
+
allAncestries
|
|
12768
|
+
);
|
|
12324
12769
|
if (!fullTree) return;
|
|
12325
12770
|
const rootNodeId = String(ancestryObject.ancestral_node);
|
|
12326
12771
|
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
@@ -12363,7 +12808,10 @@ function XViewScene({
|
|
|
12363
12808
|
const colorIndex = stateRef.current.ancestryRenderCounter % 3;
|
|
12364
12809
|
colorHex = ANCESTRY_COLORS[colorIndex];
|
|
12365
12810
|
}
|
|
12366
|
-
const resolution = new THREE3.Vector2(
|
|
12811
|
+
const resolution = new THREE3.Vector2(
|
|
12812
|
+
renderer.domElement.clientWidth,
|
|
12813
|
+
renderer.domElement.clientHeight
|
|
12814
|
+
);
|
|
12367
12815
|
const cleanupLinesForNode = (nodeId) => {
|
|
12368
12816
|
if (!ancestryEntry || !ancestryEntry.lines) return;
|
|
12369
12817
|
const linesKeep = [];
|
|
@@ -12403,7 +12851,13 @@ function XViewScene({
|
|
|
12403
12851
|
}
|
|
12404
12852
|
if (originMesh && rootNodeMesh) {
|
|
12405
12853
|
cleanupLinesForNode(rootNodeId);
|
|
12406
|
-
const branchLine = createAncestryLinkLine(
|
|
12854
|
+
const branchLine = createAncestryLinkLine(
|
|
12855
|
+
originMesh,
|
|
12856
|
+
rootNodeMesh,
|
|
12857
|
+
resolution,
|
|
12858
|
+
{},
|
|
12859
|
+
colorHex
|
|
12860
|
+
);
|
|
12407
12861
|
ancestryGroup.add(branchLine);
|
|
12408
12862
|
ancestryEntry.lines.push(branchLine);
|
|
12409
12863
|
}
|
|
@@ -12414,8 +12868,14 @@ function XViewScene({
|
|
|
12414
12868
|
if (!children || children.length === 0) return null;
|
|
12415
12869
|
let lastRenderedMesh = null;
|
|
12416
12870
|
const numChildren = children.length;
|
|
12417
|
-
const forwardVec = new THREE3.Vector3(0, 0, 1).applyAxisAngle(
|
|
12418
|
-
|
|
12871
|
+
const forwardVec = new THREE3.Vector3(0, 0, 1).applyAxisAngle(
|
|
12872
|
+
new THREE3.Vector3(0, 1, 0),
|
|
12873
|
+
currentAngle
|
|
12874
|
+
);
|
|
12875
|
+
const rightVec = new THREE3.Vector3(1, 0, 0).applyAxisAngle(
|
|
12876
|
+
new THREE3.Vector3(0, 1, 0),
|
|
12877
|
+
currentAngle
|
|
12878
|
+
);
|
|
12419
12879
|
const angleRange = numChildren > 3 ? Math.PI : Math.PI / 1.5;
|
|
12420
12880
|
children.forEach((childItem, index) => {
|
|
12421
12881
|
if (childItem.is_section) return;
|
|
@@ -12436,14 +12896,30 @@ function XViewScene({
|
|
|
12436
12896
|
targetPositionsCache.set(sNodeId, childPosition.clone());
|
|
12437
12897
|
cleanupLinesForNode(sNodeId);
|
|
12438
12898
|
}
|
|
12439
|
-
const childMesh = addOrUpdateNodeMesh(
|
|
12899
|
+
const childMesh = addOrUpdateNodeMesh(
|
|
12900
|
+
childItem.node,
|
|
12901
|
+
childPosition,
|
|
12902
|
+
true
|
|
12903
|
+
);
|
|
12440
12904
|
allRenderedNodePositions.push(childPosition);
|
|
12441
|
-
const line = createAncestryLinkLine(
|
|
12905
|
+
const line = createAncestryLinkLine(
|
|
12906
|
+
parentMesh,
|
|
12907
|
+
childMesh,
|
|
12908
|
+
resolution,
|
|
12909
|
+
childItem.relationship,
|
|
12910
|
+
colorHex
|
|
12911
|
+
);
|
|
12442
12912
|
ancestryGroup.add(line);
|
|
12443
12913
|
ancestryEntry.lines.push(line);
|
|
12444
12914
|
lastRenderedMesh = childMesh;
|
|
12445
12915
|
if (childItem.children && childItem.children.length > 0) {
|
|
12446
|
-
const lastDescendant = renderCluster(
|
|
12916
|
+
const lastDescendant = renderCluster(
|
|
12917
|
+
childItem.children,
|
|
12918
|
+
childMesh,
|
|
12919
|
+
childPosition,
|
|
12920
|
+
level + 1,
|
|
12921
|
+
currentAngle
|
|
12922
|
+
);
|
|
12447
12923
|
if (lastDescendant) lastRenderedMesh = lastDescendant;
|
|
12448
12924
|
}
|
|
12449
12925
|
});
|
|
@@ -12457,9 +12933,13 @@ function XViewScene({
|
|
|
12457
12933
|
else looseNodes.push(child);
|
|
12458
12934
|
});
|
|
12459
12935
|
}
|
|
12460
|
-
sections.sort(
|
|
12936
|
+
sections.sort(
|
|
12937
|
+
(a, b) => (a.section_numeric_id || 0) - (b.section_numeric_id || 0)
|
|
12938
|
+
);
|
|
12461
12939
|
let combinedStartNodes = [...looseNodes];
|
|
12462
|
-
let session0Index = sections.findIndex(
|
|
12940
|
+
let session0Index = sections.findIndex(
|
|
12941
|
+
(s) => s.section_numeric_id === 0 || s.name === "Sess\xE3o 0"
|
|
12942
|
+
);
|
|
12463
12943
|
if (session0Index !== -1) {
|
|
12464
12944
|
const session0 = sections[session0Index];
|
|
12465
12945
|
if (checkShouldRender(session0) && session0.children) {
|
|
@@ -12468,7 +12948,13 @@ function XViewScene({
|
|
|
12468
12948
|
sections.splice(session0Index, 1);
|
|
12469
12949
|
}
|
|
12470
12950
|
const rootTargetPos2 = targetPositionsCache.get(rootNodeId) || rootNodeMesh.position;
|
|
12471
|
-
const lastStartMesh = renderCluster(
|
|
12951
|
+
const lastStartMesh = renderCluster(
|
|
12952
|
+
combinedStartNodes,
|
|
12953
|
+
rootNodeMesh,
|
|
12954
|
+
rootTargetPos2,
|
|
12955
|
+
1,
|
|
12956
|
+
baseRotation
|
|
12957
|
+
);
|
|
12472
12958
|
if (lastStartMesh) {
|
|
12473
12959
|
currentAnchorMesh = lastStartMesh;
|
|
12474
12960
|
}
|
|
@@ -12479,10 +12965,18 @@ function XViewScene({
|
|
|
12479
12965
|
const sectionNodes = section.children || [];
|
|
12480
12966
|
if (sectionNodes.length > 0) {
|
|
12481
12967
|
const parentAngle = nodeRotationMap.get(String(currentAnchorMesh.userData.id)) ?? baseRotation;
|
|
12482
|
-
const lastMeshOfThisSection = renderCluster(
|
|
12968
|
+
const lastMeshOfThisSection = renderCluster(
|
|
12969
|
+
sectionNodes,
|
|
12970
|
+
currentAnchorMesh,
|
|
12971
|
+
currentAnchorPosition,
|
|
12972
|
+
1,
|
|
12973
|
+
parentAngle
|
|
12974
|
+
);
|
|
12483
12975
|
if (lastMeshOfThisSection) {
|
|
12484
12976
|
currentAnchorMesh = lastMeshOfThisSection;
|
|
12485
|
-
currentAnchorPosition = targetPositionsCache.get(
|
|
12977
|
+
currentAnchorPosition = targetPositionsCache.get(
|
|
12978
|
+
String(lastMeshOfThisSection.userData.id)
|
|
12979
|
+
) || lastMeshOfThisSection.position;
|
|
12486
12980
|
}
|
|
12487
12981
|
}
|
|
12488
12982
|
}
|
|
@@ -12511,7 +13005,10 @@ function XViewScene({
|
|
|
12511
13005
|
} else {
|
|
12512
13006
|
const directChildren = fullTree.children ? fullTree.children.filter((c) => !c.is_section) : [];
|
|
12513
13007
|
if (directChildren.length > 0) {
|
|
12514
|
-
targetSectionForZone = {
|
|
13008
|
+
targetSectionForZone = {
|
|
13009
|
+
name: "In\xEDcio",
|
|
13010
|
+
children: directChildren
|
|
13011
|
+
};
|
|
12515
13012
|
}
|
|
12516
13013
|
}
|
|
12517
13014
|
} else {
|
|
@@ -12585,7 +13082,10 @@ function XViewScene({
|
|
|
12585
13082
|
stateRef.current.ancestryLinks = stateRef.current.renderedAncestries.flatMap((a) => a.lines);
|
|
12586
13083
|
focusTargetPosition = center;
|
|
12587
13084
|
focusTargetRotation = baseRotation;
|
|
12588
|
-
const desiredDistance = Math.max(
|
|
13085
|
+
const desiredDistance = Math.max(
|
|
13086
|
+
x_view_config.CAMERA_ZOOM_DISTANCE,
|
|
13087
|
+
radius * 2.8
|
|
13088
|
+
);
|
|
12589
13089
|
focusZoomFactor = x_view_config.CAMERA_ZOOM_DISTANCE / desiredDistance;
|
|
12590
13090
|
} else {
|
|
12591
13091
|
const anchorId = String(currentAnchorMesh.userData.id);
|
|
@@ -12600,13 +13100,18 @@ function XViewScene({
|
|
|
12600
13100
|
}
|
|
12601
13101
|
if (!focusTargetPosition && !allowedSectionIds) {
|
|
12602
13102
|
if (allRenderedNodePositions.length > 0) {
|
|
12603
|
-
const boundingBox = new THREE3.Box3().setFromPoints(
|
|
13103
|
+
const boundingBox = new THREE3.Box3().setFromPoints(
|
|
13104
|
+
allRenderedNodePositions
|
|
13105
|
+
);
|
|
12604
13106
|
const center = new THREE3.Vector3();
|
|
12605
13107
|
boundingBox.getCenter(center);
|
|
12606
13108
|
const size = new THREE3.Vector3();
|
|
12607
13109
|
boundingBox.getSize(size);
|
|
12608
13110
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
12609
|
-
const fitZoom = Math.min(
|
|
13111
|
+
const fitZoom = Math.min(
|
|
13112
|
+
1,
|
|
13113
|
+
x_view_config.CAMERA_ZOOM_DISTANCE / (maxDim * 1.5)
|
|
13114
|
+
);
|
|
12610
13115
|
const defaultBase = new THREE3.Vector3(-50, 40, 20);
|
|
12611
13116
|
const rotatedCinematicAngle = defaultBase.clone().applyAxisAngle(new THREE3.Vector3(0, 1, 0), baseRotation);
|
|
12612
13117
|
tweenToTarget(center, fitZoom, rotatedCinematicAngle);
|
|
@@ -12625,210 +13130,280 @@ function XViewScene({
|
|
|
12625
13130
|
tweenToTarget(targetPos, focusZoomFactor, rotatedCinematicAngle);
|
|
12626
13131
|
}
|
|
12627
13132
|
},
|
|
12628
|
-
[
|
|
13133
|
+
[
|
|
13134
|
+
addOrUpdateNodeMesh,
|
|
13135
|
+
tweenToTarget,
|
|
13136
|
+
buildFullAncestryTree,
|
|
13137
|
+
readingMode.isActive,
|
|
13138
|
+
ancestryMode.isActive
|
|
13139
|
+
]
|
|
12629
13140
|
);
|
|
12630
|
-
const handleRenderAbstractionTree = useCallback4(
|
|
12631
|
-
|
|
12632
|
-
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
13141
|
+
const handleRenderAbstractionTree = useCallback4(
|
|
13142
|
+
(ancestryObject, targetNodeId = null) => {
|
|
13143
|
+
setContextMenu(
|
|
13144
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
13145
|
+
);
|
|
13146
|
+
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
13147
|
+
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
13148
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
13149
|
+
(f) => f.nodes
|
|
13150
|
+
);
|
|
13151
|
+
let fullTree = buildFullAncestryTree(
|
|
13152
|
+
ancestryObject.abstraction_tree,
|
|
13153
|
+
allParentNodes,
|
|
13154
|
+
ancestryDataRef.current
|
|
13155
|
+
);
|
|
13156
|
+
if (!fullTree || !fullTree.node) return;
|
|
13157
|
+
if (targetNodeId) {
|
|
13158
|
+
const pruneTreeToPath = (treeNode, targetId) => {
|
|
13159
|
+
var _a2;
|
|
13160
|
+
if (!treeNode) return null;
|
|
13161
|
+
const currentId = treeNode.is_section ? treeNode.section_id : String((_a2 = treeNode.node) == null ? void 0 : _a2.id);
|
|
13162
|
+
if (String(currentId) === String(targetId)) {
|
|
13163
|
+
return { ...treeNode, children: [] };
|
|
12651
13164
|
}
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
}
|
|
12658
|
-
const absId = ancestryObject.ancestry_id + "_abs";
|
|
12659
|
-
handleClearAncestryVisuals(absId);
|
|
12660
|
-
const colorHex = 9133302;
|
|
12661
|
-
const resolution = new THREE3.Vector2(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
|
|
12662
|
-
const ancestryEntry = { id: absId, lines: [], isFullRender: true };
|
|
12663
|
-
renderedAncestries.push(ancestryEntry);
|
|
12664
|
-
const rootNodeId = String(fullTree.node.id);
|
|
12665
|
-
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
12666
|
-
let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
|
|
12667
|
-
if (!rootNodeMesh) {
|
|
12668
|
-
rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
|
|
12669
|
-
}
|
|
12670
|
-
const SPACING_Y = -40;
|
|
12671
|
-
const SPACING_X = 55;
|
|
12672
|
-
const renderVertical = (treeNode, parentMesh, parentPos, level) => {
|
|
12673
|
-
if (!treeNode.children || treeNode.children.length === 0) return;
|
|
12674
|
-
const totalSiblings = treeNode.children.length;
|
|
12675
|
-
treeNode.children.forEach((childItem, i) => {
|
|
12676
|
-
if (!childItem.node) return;
|
|
12677
|
-
const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
|
|
12678
|
-
const childY = parentPos.y + SPACING_Y;
|
|
12679
|
-
const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
|
|
12680
|
-
const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
|
|
12681
|
-
const line = createAncestryLinkLine(parentMesh, childMesh, resolution, {}, colorHex);
|
|
12682
|
-
ancestryGroup.add(line);
|
|
12683
|
-
ancestryEntry.lines.push(line);
|
|
12684
|
-
renderVertical(childItem, childMesh, childPos, level + 1);
|
|
12685
|
-
});
|
|
12686
|
-
};
|
|
12687
|
-
renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
|
|
12688
|
-
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
12689
|
-
tweenToTarget(rootTargetPos, 0.7);
|
|
12690
|
-
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
12691
|
-
const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
|
|
12692
|
-
const { ancestry, branchStack } = readingMode;
|
|
12693
|
-
if (!ancestry || !ancestry.tree) return;
|
|
12694
|
-
const allAncestries = ancestryDataRef.current || [];
|
|
12695
|
-
const fullTree = buildFullAncestryTree(ancestry.tree, Object.values(parentDataRef.current).flatMap((f) => f.nodes), allAncestries);
|
|
12696
|
-
if (action === "open") {
|
|
12697
|
-
let currentPtr = fullTree;
|
|
12698
|
-
for (const step of branchStack) {
|
|
12699
|
-
const found = findNodePath3(currentPtr, step.nodeId);
|
|
12700
|
-
if (found && found.node.parallel_branches) {
|
|
12701
|
-
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
12702
|
-
if (branch) currentPtr = branch.tree;
|
|
12703
|
-
}
|
|
12704
|
-
}
|
|
12705
|
-
const foundTarget = findNodePath3(currentPtr, nodeId);
|
|
12706
|
-
if (foundTarget && foundTarget.node && foundTarget.node.parallel_branches && foundTarget.node.parallel_branches.length > 0) {
|
|
12707
|
-
const branchToOpen = foundTarget.node.parallel_branches.find((b) => (b.direction || "right") === direction);
|
|
12708
|
-
if (!branchToOpen) return;
|
|
12709
|
-
if (branchToOpen && branchToOpen.tree) {
|
|
12710
|
-
const parentIndexToSave = stateRef.current.readMode.currentMaxIndex;
|
|
12711
|
-
const savedBranchProgress = 0;
|
|
12712
|
-
stateRef.current.readMode.currentMaxIndex = savedBranchProgress;
|
|
12713
|
-
stateRef.current.maxAncestryRenderIndex = savedBranchProgress;
|
|
12714
|
-
const newStack = [...branchStack, {
|
|
12715
|
-
nodeId,
|
|
12716
|
-
branchId: branchToOpen.id,
|
|
12717
|
-
savedMaxIndex: parentIndexToSave,
|
|
12718
|
-
entryDirection: direction
|
|
12719
|
-
}];
|
|
12720
|
-
setReadingMode((prev) => ({ ...prev, branchStack: newStack, initialSectionId: null }));
|
|
12721
|
-
const branchAncestryObj = {
|
|
12722
|
-
ancestry_id: branchToOpen.id,
|
|
12723
|
-
ancestral_node: branchToOpen.tree.node.id,
|
|
12724
|
-
name: branchToOpen.name,
|
|
12725
|
-
description: branchToOpen.description,
|
|
12726
|
-
description_sections: branchToOpen.description_sections,
|
|
12727
|
-
tree: branchToOpen.tree,
|
|
12728
|
-
_originNodeId: nodeId,
|
|
12729
|
-
_branchDirection: direction
|
|
12730
|
-
};
|
|
12731
|
-
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
12732
|
-
const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
|
|
12733
|
-
for (let i = 0; i <= savedBranchProgress; i++) {
|
|
12734
|
-
if (branchSections[i]) {
|
|
12735
|
-
if (branchSections[i].id) allowedIds.add(String(branchSections[i].id));
|
|
12736
|
-
if (branchSections[i].numericId !== void 0 && branchSections[i].numericId !== null) {
|
|
12737
|
-
allowedIds.add(branchSections[i].numericId);
|
|
12738
|
-
allowedIds.add(String(branchSections[i].numericId));
|
|
13165
|
+
if (treeNode.children && treeNode.children.length > 0) {
|
|
13166
|
+
for (let child of treeNode.children) {
|
|
13167
|
+
const prunedChild = pruneTreeToPath(child, targetId);
|
|
13168
|
+
if (prunedChild) {
|
|
13169
|
+
return { ...treeNode, children: [prunedChild] };
|
|
12739
13170
|
}
|
|
12740
13171
|
}
|
|
12741
13172
|
}
|
|
12742
|
-
|
|
12743
|
-
|
|
12744
|
-
|
|
12745
|
-
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12753
|
-
|
|
13173
|
+
return null;
|
|
13174
|
+
};
|
|
13175
|
+
const pruned = pruneTreeToPath(fullTree, targetNodeId);
|
|
13176
|
+
if (pruned) fullTree = pruned;
|
|
13177
|
+
}
|
|
13178
|
+
const absId = ancestryObject.ancestry_id + "_abs";
|
|
13179
|
+
handleClearAncestryVisuals(absId);
|
|
13180
|
+
const colorHex = 9133302;
|
|
13181
|
+
const resolution = new THREE3.Vector2(
|
|
13182
|
+
renderer.domElement.clientWidth,
|
|
13183
|
+
renderer.domElement.clientHeight
|
|
13184
|
+
);
|
|
13185
|
+
const ancestryEntry = { id: absId, lines: [], isFullRender: true };
|
|
13186
|
+
renderedAncestries.push(ancestryEntry);
|
|
13187
|
+
const rootNodeId = String(fullTree.node.id);
|
|
13188
|
+
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
13189
|
+
let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
|
|
13190
|
+
if (!rootNodeMesh) {
|
|
13191
|
+
rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
|
|
12754
13192
|
}
|
|
12755
|
-
|
|
12756
|
-
|
|
12757
|
-
const
|
|
12758
|
-
|
|
12759
|
-
|
|
12760
|
-
|
|
12761
|
-
|
|
12762
|
-
|
|
12763
|
-
|
|
12764
|
-
|
|
12765
|
-
|
|
12766
|
-
|
|
12767
|
-
|
|
12768
|
-
|
|
12769
|
-
|
|
12770
|
-
|
|
13193
|
+
const SPACING_Y = -40;
|
|
13194
|
+
const SPACING_X = 55;
|
|
13195
|
+
const renderVertical = (treeNode, parentMesh, parentPos, level) => {
|
|
13196
|
+
if (!treeNode.children || treeNode.children.length === 0) return;
|
|
13197
|
+
const totalSiblings = treeNode.children.length;
|
|
13198
|
+
treeNode.children.forEach((childItem, i) => {
|
|
13199
|
+
if (!childItem.node) return;
|
|
13200
|
+
const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
|
|
13201
|
+
const childY = parentPos.y + SPACING_Y;
|
|
13202
|
+
const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
|
|
13203
|
+
const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
|
|
13204
|
+
const line = createAncestryLinkLine(
|
|
13205
|
+
parentMesh,
|
|
13206
|
+
childMesh,
|
|
13207
|
+
resolution,
|
|
13208
|
+
{},
|
|
13209
|
+
colorHex
|
|
13210
|
+
);
|
|
13211
|
+
ancestryGroup.add(line);
|
|
13212
|
+
ancestryEntry.lines.push(line);
|
|
13213
|
+
renderVertical(childItem, childMesh, childPos, level + 1);
|
|
13214
|
+
});
|
|
13215
|
+
};
|
|
13216
|
+
renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
|
|
13217
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
13218
|
+
(a) => a.lines
|
|
13219
|
+
);
|
|
13220
|
+
tweenToTarget(rootTargetPos, 0.7);
|
|
13221
|
+
},
|
|
13222
|
+
[
|
|
13223
|
+
addOrUpdateNodeMesh,
|
|
13224
|
+
tweenToTarget,
|
|
13225
|
+
buildFullAncestryTree,
|
|
13226
|
+
handleClearAncestryVisuals
|
|
13227
|
+
]
|
|
13228
|
+
);
|
|
13229
|
+
const handleReadModeBranchNav = useCallback4(
|
|
13230
|
+
(nodeId, action, direction = "right") => {
|
|
13231
|
+
const { ancestry, branchStack } = readingMode;
|
|
13232
|
+
if (!ancestry || !ancestry.tree) return;
|
|
13233
|
+
const allAncestries = ancestryDataRef.current || [];
|
|
13234
|
+
const fullTree = buildFullAncestryTree(
|
|
13235
|
+
ancestry.tree,
|
|
13236
|
+
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
13237
|
+
allAncestries
|
|
13238
|
+
);
|
|
13239
|
+
if (action === "open") {
|
|
13240
|
+
let currentPtr = fullTree;
|
|
13241
|
+
for (const step of branchStack) {
|
|
13242
|
+
const found = findNodePath3(currentPtr, step.nodeId);
|
|
12771
13243
|
if (found && found.node.parallel_branches) {
|
|
12772
|
-
const branch = found.node.parallel_branches.find(
|
|
12773
|
-
|
|
12774
|
-
|
|
12775
|
-
|
|
13244
|
+
const branch = found.node.parallel_branches.find(
|
|
13245
|
+
(b) => b.id === step.branchId
|
|
13246
|
+
);
|
|
13247
|
+
if (branch) currentPtr = branch.tree;
|
|
13248
|
+
}
|
|
13249
|
+
}
|
|
13250
|
+
const foundTarget = findNodePath3(currentPtr, nodeId);
|
|
13251
|
+
if (foundTarget && foundTarget.node && foundTarget.node.parallel_branches && foundTarget.node.parallel_branches.length > 0) {
|
|
13252
|
+
const branchToOpen = foundTarget.node.parallel_branches.find(
|
|
13253
|
+
(b) => (b.direction || "right") === direction
|
|
13254
|
+
);
|
|
13255
|
+
if (!branchToOpen) return;
|
|
13256
|
+
if (branchToOpen && branchToOpen.tree) {
|
|
13257
|
+
const parentIndexToSave = stateRef.current.readMode.currentMaxIndex;
|
|
13258
|
+
const savedBranchProgress = 0;
|
|
13259
|
+
stateRef.current.readMode.currentMaxIndex = savedBranchProgress;
|
|
13260
|
+
stateRef.current.maxAncestryRenderIndex = savedBranchProgress;
|
|
13261
|
+
const newStack = [
|
|
13262
|
+
...branchStack,
|
|
13263
|
+
{
|
|
13264
|
+
nodeId,
|
|
13265
|
+
branchId: branchToOpen.id,
|
|
13266
|
+
savedMaxIndex: parentIndexToSave,
|
|
13267
|
+
entryDirection: direction
|
|
13268
|
+
}
|
|
13269
|
+
];
|
|
13270
|
+
setReadingMode((prev) => ({
|
|
13271
|
+
...prev,
|
|
13272
|
+
branchStack: newStack,
|
|
13273
|
+
initialSectionId: null
|
|
13274
|
+
}));
|
|
13275
|
+
const branchAncestryObj = {
|
|
13276
|
+
ancestry_id: branchToOpen.id,
|
|
13277
|
+
ancestral_node: branchToOpen.tree.node.id,
|
|
13278
|
+
name: branchToOpen.name,
|
|
13279
|
+
description: branchToOpen.description,
|
|
13280
|
+
description_sections: branchToOpen.description_sections,
|
|
13281
|
+
tree: branchToOpen.tree,
|
|
13282
|
+
_originNodeId: nodeId,
|
|
13283
|
+
_branchDirection: direction
|
|
13284
|
+
};
|
|
13285
|
+
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
13286
|
+
const branchSections = parseDescriptionSections(
|
|
13287
|
+
branchToOpen.description || "",
|
|
13288
|
+
branchToOpen.description_sections || []
|
|
13289
|
+
);
|
|
13290
|
+
for (let i = 0; i <= savedBranchProgress; i++) {
|
|
13291
|
+
if (branchSections[i]) {
|
|
13292
|
+
if (branchSections[i].id)
|
|
13293
|
+
allowedIds.add(String(branchSections[i].id));
|
|
13294
|
+
if (branchSections[i].numericId !== void 0 && branchSections[i].numericId !== null) {
|
|
13295
|
+
allowedIds.add(branchSections[i].numericId);
|
|
13296
|
+
allowedIds.add(String(branchSections[i].numericId));
|
|
13297
|
+
}
|
|
13298
|
+
}
|
|
12776
13299
|
}
|
|
13300
|
+
const rotation = newStack.reduce((acc, step) => {
|
|
13301
|
+
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
13302
|
+
}, 0);
|
|
13303
|
+
const initialFocusId = "preamble";
|
|
13304
|
+
handleRenderAncestry(
|
|
13305
|
+
branchAncestryObj,
|
|
13306
|
+
allowedIds,
|
|
13307
|
+
initialFocusId,
|
|
13308
|
+
rotation,
|
|
13309
|
+
false
|
|
13310
|
+
);
|
|
12777
13311
|
}
|
|
12778
13312
|
}
|
|
12779
|
-
|
|
12780
|
-
|
|
12781
|
-
|
|
12782
|
-
|
|
12783
|
-
|
|
12784
|
-
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
13313
|
+
} else if (action === "back") {
|
|
13314
|
+
if (branchStack.length === 0) return;
|
|
13315
|
+
const newStack = [...branchStack];
|
|
13316
|
+
const popped = newStack.pop();
|
|
13317
|
+
if (popped && popped.branchId) {
|
|
13318
|
+
stateRef.current.readMode.progressMap[popped.branchId] = stateRef.current.readMode.currentMaxIndex;
|
|
13319
|
+
}
|
|
13320
|
+
const parentSavedIndex = popped.savedMaxIndex !== void 0 ? popped.savedMaxIndex : 0;
|
|
13321
|
+
stateRef.current.readMode.currentMaxIndex = parentSavedIndex;
|
|
13322
|
+
stateRef.current.maxAncestryRenderIndex = parentSavedIndex;
|
|
13323
|
+
let targetTreeToRender = fullTree;
|
|
13324
|
+
let targetAncestryInfo = ancestry;
|
|
13325
|
+
if (newStack.length > 0) {
|
|
13326
|
+
let ptr = fullTree;
|
|
13327
|
+
for (const step of newStack) {
|
|
13328
|
+
const found = findNodePath3(ptr, step.nodeId);
|
|
13329
|
+
if (found && found.node.parallel_branches) {
|
|
13330
|
+
const branch = found.node.parallel_branches.find(
|
|
13331
|
+
(b) => b.id === step.branchId
|
|
13332
|
+
);
|
|
13333
|
+
if (branch) {
|
|
13334
|
+
ptr = branch.tree;
|
|
13335
|
+
targetAncestryInfo = {
|
|
13336
|
+
...branch,
|
|
13337
|
+
ancestry_id: branch.id,
|
|
13338
|
+
ancestral_node: branch.tree.node.id
|
|
13339
|
+
};
|
|
13340
|
+
}
|
|
13341
|
+
}
|
|
13342
|
+
}
|
|
13343
|
+
targetTreeToRender = ptr;
|
|
13344
|
+
}
|
|
13345
|
+
const activeParentStackItem = newStack.length > 0 ? newStack[newStack.length - 1] : null;
|
|
13346
|
+
const parentAncestryObj = {
|
|
13347
|
+
...targetAncestryInfo,
|
|
13348
|
+
tree: targetTreeToRender,
|
|
13349
|
+
_originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
|
|
13350
|
+
_branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
|
|
13351
|
+
};
|
|
13352
|
+
const descriptionText = targetAncestryInfo.description || "";
|
|
13353
|
+
const savedSections = targetAncestryInfo.description_sections || [];
|
|
13354
|
+
const sections = parseDescriptionSections(
|
|
13355
|
+
descriptionText,
|
|
13356
|
+
savedSections
|
|
13357
|
+
);
|
|
13358
|
+
let focusTargetId = null;
|
|
13359
|
+
if (popped && popped.nodeId) {
|
|
13360
|
+
const mentionTag = `[[MENTION:node:${popped.nodeId}]]`;
|
|
13361
|
+
for (let i = 0; i < sections.length; i++) {
|
|
13362
|
+
if (sections[i].content && sections[i].content.includes(mentionTag)) {
|
|
13363
|
+
const section = sections[i];
|
|
13364
|
+
focusTargetId = section.numericId !== void 0 ? section.numericId : section.id;
|
|
13365
|
+
break;
|
|
13366
|
+
}
|
|
12799
13367
|
}
|
|
12800
13368
|
}
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12807
|
-
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
13369
|
+
const allowedIds = /* @__PURE__ */ new Set();
|
|
13370
|
+
allowedIds.add("preamble");
|
|
13371
|
+
allowedIds.add(0);
|
|
13372
|
+
allowedIds.add("0");
|
|
13373
|
+
for (let i = 0; i <= parentSavedIndex; i++) {
|
|
13374
|
+
if (sections[i]) {
|
|
13375
|
+
if (sections[i].id) allowedIds.add(String(sections[i].id));
|
|
13376
|
+
if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
|
|
13377
|
+
allowedIds.add(sections[i].numericId);
|
|
13378
|
+
allowedIds.add(String(sections[i].numericId));
|
|
13379
|
+
}
|
|
12812
13380
|
}
|
|
12813
13381
|
}
|
|
12814
|
-
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
|
|
12821
|
-
|
|
12822
|
-
|
|
13382
|
+
const rotation = newStack.reduce((acc, step) => {
|
|
13383
|
+
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
13384
|
+
}, 0);
|
|
13385
|
+
handleRenderAncestry(
|
|
13386
|
+
parentAncestryObj,
|
|
13387
|
+
allowedIds,
|
|
13388
|
+
focusTargetId,
|
|
13389
|
+
rotation,
|
|
13390
|
+
false
|
|
13391
|
+
);
|
|
13392
|
+
if (popped && popped.nodeId) {
|
|
13393
|
+
const nodeMesh = stateRef.current.nodeObjects[String(popped.nodeId)];
|
|
13394
|
+
if (nodeMesh) {
|
|
13395
|
+
tweenToTarget(nodeMesh);
|
|
13396
|
+
}
|
|
12823
13397
|
}
|
|
13398
|
+
setReadingMode((prev) => ({
|
|
13399
|
+
...prev,
|
|
13400
|
+
branchStack: newStack,
|
|
13401
|
+
initialSectionId: focusTargetId
|
|
13402
|
+
}));
|
|
12824
13403
|
}
|
|
12825
|
-
|
|
12826
|
-
|
|
12827
|
-
|
|
12828
|
-
initialSectionId: focusTargetId
|
|
12829
|
-
}));
|
|
12830
|
-
}
|
|
12831
|
-
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
13404
|
+
},
|
|
13405
|
+
[readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]
|
|
13406
|
+
);
|
|
12832
13407
|
const handleReadModeHighlight = useCallback4((nodeId) => {
|
|
12833
13408
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
12834
13409
|
stateRef.current.highlightedNodeId = nodeId;
|
|
@@ -12836,7 +13411,8 @@ function XViewScene({
|
|
|
12836
13411
|
setHighlightedNodeId(nodeId);
|
|
12837
13412
|
}, []);
|
|
12838
13413
|
const activeNodeBranches = useMemo12(() => {
|
|
12839
|
-
if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
|
|
13414
|
+
if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
|
|
13415
|
+
return null;
|
|
12840
13416
|
const fullTree = buildFullAncestryTree(
|
|
12841
13417
|
readingMode.ancestry.tree,
|
|
12842
13418
|
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
@@ -12871,7 +13447,13 @@ function XViewScene({
|
|
|
12871
13447
|
};
|
|
12872
13448
|
}
|
|
12873
13449
|
return null;
|
|
12874
|
-
}, [
|
|
13450
|
+
}, [
|
|
13451
|
+
highlightedNodeId,
|
|
13452
|
+
readingMode.ancestry,
|
|
13453
|
+
buildFullAncestryTree,
|
|
13454
|
+
readingMode.branchStack,
|
|
13455
|
+
ancestryDataRef.current
|
|
13456
|
+
]);
|
|
12875
13457
|
const backNavigationInfo = useMemo12(() => {
|
|
12876
13458
|
const { branchStack } = readingMode;
|
|
12877
13459
|
if (!branchStack || branchStack.length === 0) return null;
|
|
@@ -12907,7 +13489,9 @@ function XViewScene({
|
|
|
12907
13489
|
for (const step of branchStack) {
|
|
12908
13490
|
const found = findNodePath3(currentPtr, step.nodeId);
|
|
12909
13491
|
if (found && found.node.parallel_branches) {
|
|
12910
|
-
const branch = found.node.parallel_branches.find(
|
|
13492
|
+
const branch = found.node.parallel_branches.find(
|
|
13493
|
+
(b) => b.id === step.branchId
|
|
13494
|
+
);
|
|
12911
13495
|
if (branch) {
|
|
12912
13496
|
currentPtr = branch.tree;
|
|
12913
13497
|
currentMeta = branch;
|
|
@@ -12928,17 +13512,26 @@ function XViewScene({
|
|
|
12928
13512
|
if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
|
|
12929
13513
|
return null;
|
|
12930
13514
|
}
|
|
12931
|
-
const allNodes = Object.values(parentDataRef.current || {}).flatMap(
|
|
13515
|
+
const allNodes = Object.values(parentDataRef.current || {}).flatMap(
|
|
13516
|
+
(f) => f.nodes || []
|
|
13517
|
+
);
|
|
12932
13518
|
const allAncestries = ancestryDataRef.current || [];
|
|
12933
13519
|
return buildFullAncestryTree(
|
|
12934
13520
|
readingMode.ancestry.abstraction_tree,
|
|
12935
13521
|
allNodes,
|
|
12936
13522
|
allAncestries
|
|
12937
13523
|
);
|
|
12938
|
-
}, [
|
|
13524
|
+
}, [
|
|
13525
|
+
readingMode.isActive,
|
|
13526
|
+
readingMode.ancestry,
|
|
13527
|
+
buildFullAncestryTree,
|
|
13528
|
+
sceneVersion
|
|
13529
|
+
]);
|
|
12939
13530
|
const handleStartReadingAncestry = useCallback4(
|
|
12940
13531
|
async (ancestryObject) => {
|
|
12941
|
-
setContextMenu(
|
|
13532
|
+
setContextMenu(
|
|
13533
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
13534
|
+
);
|
|
12942
13535
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
12943
13536
|
console.warn("Ancestralidade inv\xE1lida para leitura.");
|
|
12944
13537
|
return;
|
|
@@ -12953,7 +13546,7 @@ function XViewScene({
|
|
|
12953
13546
|
const hasAbstractionNodes = ancestryObject.abstraction_tree && ancestryObject.abstraction_tree.children && ancestryObject.abstraction_tree.children.length > 0;
|
|
12954
13547
|
const shouldAutoRenderAbstraction = !hasDescription && !hasMainTreeNodes && hasAbstractionNodes;
|
|
12955
13548
|
setReadingMode({
|
|
12956
|
-
isActive:
|
|
13549
|
+
isActive: hasDescription,
|
|
12957
13550
|
ancestry: ancestryObject,
|
|
12958
13551
|
branchStack: [],
|
|
12959
13552
|
autoAbstraction: shouldAutoRenderAbstraction
|
|
@@ -12971,148 +13564,190 @@ function XViewScene({
|
|
|
12971
13564
|
},
|
|
12972
13565
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
12973
13566
|
);
|
|
12974
|
-
const handleReadModeSectionChange = useCallback4(
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
13567
|
+
const handleReadModeSectionChange = useCallback4(
|
|
13568
|
+
(activeSectionId) => {
|
|
13569
|
+
const { ancestry, branchStack } = readingMode;
|
|
13570
|
+
if (!ancestry || !readingMode.isActive) return;
|
|
13571
|
+
let targetObj = ancestry;
|
|
13572
|
+
let targetTree = ancestry.tree;
|
|
13573
|
+
if (branchStack.length > 0) {
|
|
13574
|
+
const allNodes = Object.values(parentDataRef.current).flatMap(
|
|
13575
|
+
(f) => f.nodes
|
|
13576
|
+
);
|
|
13577
|
+
const fullTree = buildFullAncestryTree(
|
|
13578
|
+
ancestry.tree,
|
|
13579
|
+
allNodes,
|
|
13580
|
+
ancestryDataRef.current
|
|
13581
|
+
);
|
|
13582
|
+
let currentPtr = fullTree;
|
|
13583
|
+
for (const step of branchStack) {
|
|
13584
|
+
const found = findNodePath3(currentPtr, step.nodeId);
|
|
13585
|
+
if (found && found.node && found.node.parallel_branches) {
|
|
13586
|
+
const branch = found.node.parallel_branches.find(
|
|
13587
|
+
(b) => b.id === step.branchId
|
|
13588
|
+
);
|
|
13589
|
+
if (branch) {
|
|
13590
|
+
targetObj = branch;
|
|
13591
|
+
targetTree = branch.tree;
|
|
13592
|
+
currentPtr = branch.tree;
|
|
13593
|
+
}
|
|
12995
13594
|
}
|
|
12996
13595
|
}
|
|
12997
13596
|
}
|
|
12998
|
-
|
|
12999
|
-
|
|
13000
|
-
|
|
13001
|
-
|
|
13002
|
-
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13012
|
-
|
|
13013
|
-
|
|
13014
|
-
|
|
13015
|
-
|
|
13016
|
-
|
|
13017
|
-
|
|
13018
|
-
|
|
13019
|
-
allowedIds.add(String(sections[i].
|
|
13597
|
+
const descriptionText = targetObj.description || "";
|
|
13598
|
+
const savedSections = targetObj.description_sections || [];
|
|
13599
|
+
const sections = parseDescriptionSections(descriptionText, savedSections);
|
|
13600
|
+
let activeIndex = sections.findIndex(
|
|
13601
|
+
(s) => String(s.id) === String(activeSectionId)
|
|
13602
|
+
);
|
|
13603
|
+
if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
|
|
13604
|
+
activeIndex = sections.findIndex(
|
|
13605
|
+
(s) => s.numericId === parseInt(activeSectionId)
|
|
13606
|
+
);
|
|
13607
|
+
}
|
|
13608
|
+
if (activeIndex === -1) activeIndex = 0;
|
|
13609
|
+
stateRef.current.readMode.currentMaxIndex = activeIndex;
|
|
13610
|
+
stateRef.current.maxAncestryRenderIndex = activeIndex;
|
|
13611
|
+
const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
|
|
13612
|
+
const allowedIds = /* @__PURE__ */ new Set();
|
|
13613
|
+
allowedIds.add("preamble");
|
|
13614
|
+
allowedIds.add(0);
|
|
13615
|
+
allowedIds.add("0");
|
|
13616
|
+
for (let i = 0; i <= renderLimitIndex; i++) {
|
|
13617
|
+
if (sections[i]) {
|
|
13618
|
+
if (sections[i].id) allowedIds.add(String(sections[i].id));
|
|
13619
|
+
if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
|
|
13620
|
+
allowedIds.add(sections[i].numericId);
|
|
13621
|
+
allowedIds.add(String(sections[i].numericId));
|
|
13622
|
+
}
|
|
13020
13623
|
}
|
|
13021
13624
|
}
|
|
13022
|
-
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13625
|
+
const activeSection = sections[activeIndex];
|
|
13626
|
+
let focusTargetId = activeSectionId;
|
|
13627
|
+
if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
|
|
13628
|
+
focusTargetId = activeSection.numericId;
|
|
13629
|
+
}
|
|
13630
|
+
const currentStackItem = branchStack.length > 0 ? branchStack[branchStack.length - 1] : null;
|
|
13631
|
+
const renderPayload = {
|
|
13632
|
+
...targetObj,
|
|
13633
|
+
ancestry_id: targetObj.ancestry_id || targetObj.id,
|
|
13634
|
+
ancestral_node: targetTree.node ? targetTree.node.id : targetTree.node_id,
|
|
13635
|
+
tree: targetTree,
|
|
13636
|
+
_originNodeId: currentStackItem ? currentStackItem.nodeId : null,
|
|
13637
|
+
_branchDirection: currentStackItem ? currentStackItem.entryDirection : null,
|
|
13638
|
+
_forceUpdate: true
|
|
13639
|
+
};
|
|
13640
|
+
const rotation = branchStack.reduce((acc, step) => {
|
|
13641
|
+
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
13642
|
+
}, 0);
|
|
13643
|
+
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
13644
|
+
},
|
|
13645
|
+
[
|
|
13646
|
+
readingMode,
|
|
13647
|
+
handleRenderAncestry,
|
|
13648
|
+
buildFullAncestryTree,
|
|
13649
|
+
ancestryDataRef.current
|
|
13650
|
+
]
|
|
13651
|
+
);
|
|
13043
13652
|
const handleCloseReadMode = useCallback4(() => {
|
|
13044
13653
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
13045
13654
|
}, []);
|
|
13046
|
-
const handleAncestrySectionChange = useCallback4(
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13655
|
+
const handleAncestrySectionChange = useCallback4(
|
|
13656
|
+
(activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
13657
|
+
var _a2, _b2;
|
|
13658
|
+
const currentMode = stateRef.current.ancestry;
|
|
13659
|
+
let targetObj = ancestryOverride;
|
|
13660
|
+
if (!targetObj) {
|
|
13661
|
+
const currentAncestryId = currentMode.currentAncestryId;
|
|
13662
|
+
const ancestryObj = (ancestryDataRef.current || []).find(
|
|
13663
|
+
(a) => String(a.ancestry_id) === String(currentAncestryId)
|
|
13664
|
+
);
|
|
13665
|
+
targetObj = ancestryObj || (currentMode.isActive ? {
|
|
13666
|
+
...currentMode,
|
|
13667
|
+
ancestry_id: "temp_creating",
|
|
13668
|
+
ancestral_node: (_b2 = (_a2 = currentMode.tree) == null ? void 0 : _a2.node) == null ? void 0 : _b2.id
|
|
13669
|
+
} : null);
|
|
13670
|
+
}
|
|
13671
|
+
if (!targetObj) return;
|
|
13672
|
+
const targetId = targetObj.ancestry_id || targetObj.id;
|
|
13673
|
+
if (stateRef.current.lastRenderedAncestryId !== targetId) {
|
|
13674
|
+
stateRef.current.maxAncestryRenderIndex = 0;
|
|
13675
|
+
stateRef.current.lastRenderedAncestryId = targetId;
|
|
13676
|
+
}
|
|
13677
|
+
const descriptionText = (ancestryOverride ? targetObj.description : currentMode.ancestryDescription) || targetObj.description || "";
|
|
13678
|
+
const savedSections = (ancestryOverride ? targetObj.description_sections : currentMode.ancestryDescriptionSections) || targetObj.description_sections || [];
|
|
13679
|
+
const sections = parseDescriptionSections(descriptionText, savedSections);
|
|
13680
|
+
let activeIndex = sections.findIndex(
|
|
13681
|
+
(s) => String(s.id) === String(activeSectionId)
|
|
13682
|
+
);
|
|
13683
|
+
if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
|
|
13684
|
+
activeIndex = sections.findIndex(
|
|
13685
|
+
(s) => s.numericId === parseInt(activeSectionId)
|
|
13686
|
+
);
|
|
13687
|
+
}
|
|
13688
|
+
if (activeIndex === -1) activeIndex = 0;
|
|
13689
|
+
if (stateRef.current.maxAncestryRenderIndex === void 0)
|
|
13690
|
+
stateRef.current.maxAncestryRenderIndex = 0;
|
|
13691
|
+
stateRef.current.maxAncestryRenderIndex = activeIndex;
|
|
13692
|
+
const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
|
|
13693
|
+
const allowedIds = /* @__PURE__ */ new Set();
|
|
13694
|
+
allowedIds.add("preamble");
|
|
13695
|
+
allowedIds.add(0);
|
|
13696
|
+
allowedIds.add("0");
|
|
13697
|
+
for (let i = 0; i <= renderLimitIndex; i++) {
|
|
13698
|
+
if (sections[i]) {
|
|
13699
|
+
if (sections[i].id) allowedIds.add(String(sections[i].id));
|
|
13700
|
+
if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
|
|
13701
|
+
allowedIds.add(sections[i].numericId);
|
|
13702
|
+
allowedIds.add(String(sections[i].numericId));
|
|
13703
|
+
}
|
|
13086
13704
|
}
|
|
13087
13705
|
}
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13706
|
+
const activeSection = sections[activeIndex];
|
|
13707
|
+
let focusTargetId = activeSectionId;
|
|
13708
|
+
if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
|
|
13709
|
+
focusTargetId = activeSection.numericId;
|
|
13710
|
+
}
|
|
13711
|
+
const treeToRender = ancestryOverride ? ancestryOverride.tree : currentMode.isActive && currentMode.tree ? currentMode.tree : targetObj.tree;
|
|
13712
|
+
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
13713
|
+
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
13714
|
+
},
|
|
13715
|
+
[handleRenderAncestry]
|
|
13716
|
+
);
|
|
13098
13717
|
const handleEditAncestry = useCallback4(
|
|
13099
13718
|
async (ancestryObject) => {
|
|
13100
|
-
setContextMenu(
|
|
13719
|
+
setContextMenu(
|
|
13720
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
13721
|
+
);
|
|
13101
13722
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
13102
|
-
alert(
|
|
13723
|
+
alert(
|
|
13724
|
+
"N\xE3o foi poss\xEDvel carregar os dados desta ancestralidade para edi\xE7\xE3o."
|
|
13725
|
+
);
|
|
13103
13726
|
return;
|
|
13104
13727
|
}
|
|
13105
13728
|
stateRef.current.maxAncestryRenderIndex = 0;
|
|
13106
13729
|
const initialSections = /* @__PURE__ */ new Set(["preamble", 0]);
|
|
13107
13730
|
await handleRenderAncestry(ancestryObject, initialSections);
|
|
13108
|
-
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
13731
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
13732
|
+
(fileData) => fileData.nodes
|
|
13733
|
+
);
|
|
13109
13734
|
const allAncestries = ancestryDataRef.current || [];
|
|
13110
|
-
const fullTree = buildFullAncestryTree(
|
|
13735
|
+
const fullTree = buildFullAncestryTree(
|
|
13736
|
+
ancestryObject.tree,
|
|
13737
|
+
allParentNodes,
|
|
13738
|
+
allAncestries
|
|
13739
|
+
);
|
|
13111
13740
|
if (!fullTree) {
|
|
13112
|
-
alert(
|
|
13741
|
+
alert(
|
|
13742
|
+
"Falha ao reconstruir a \xE1rvore de ancestralidade. Alguns Nodes podem estar faltando."
|
|
13743
|
+
);
|
|
13113
13744
|
return;
|
|
13114
13745
|
}
|
|
13115
|
-
const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(
|
|
13746
|
+
const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(
|
|
13747
|
+
ancestryObject.abstraction_tree,
|
|
13748
|
+
allParentNodes,
|
|
13749
|
+
allAncestries
|
|
13750
|
+
) : { node: fullTree.node, children: [] };
|
|
13116
13751
|
setAncestryMode({
|
|
13117
13752
|
isActive: true,
|
|
13118
13753
|
...ancestryObject,
|
|
@@ -13164,7 +13799,9 @@ function XViewScene({
|
|
|
13164
13799
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
13165
13800
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
13166
13801
|
if (!treeToUse || !treeToUse.node) {
|
|
13167
|
-
alert(
|
|
13802
|
+
alert(
|
|
13803
|
+
"Erro: A estrutura da ancestralidade \xE9 inv\xE1lida (Node raiz ausente)."
|
|
13804
|
+
);
|
|
13168
13805
|
return;
|
|
13169
13806
|
}
|
|
13170
13807
|
if (!save_view_data || !stateRef.current.nodeIdToParentFileMap) return;
|
|
@@ -13197,14 +13834,18 @@ function XViewScene({
|
|
|
13197
13834
|
};
|
|
13198
13835
|
};
|
|
13199
13836
|
const treeWithIds = convertTreeToIds(treeToUse);
|
|
13200
|
-
const abstractionTreeWithIds = convertTreeToIds(
|
|
13837
|
+
const abstractionTreeWithIds = convertTreeToIds(
|
|
13838
|
+
ancestryMode.abstraction_tree
|
|
13839
|
+
);
|
|
13201
13840
|
if (!treeWithIds) {
|
|
13202
13841
|
alert("Erro ao processar a \xE1rvore da ancestralidade.");
|
|
13203
13842
|
return;
|
|
13204
13843
|
}
|
|
13205
13844
|
let originalAncestryObj = null;
|
|
13206
13845
|
if (isEditMode && currentAncestryId) {
|
|
13207
|
-
originalAncestryObj = (ancestryDataRef.current || []).find(
|
|
13846
|
+
originalAncestryObj = (ancestryDataRef.current || []).find(
|
|
13847
|
+
(anc) => String(anc.ancestry_id) === String(currentAncestryId)
|
|
13848
|
+
);
|
|
13208
13849
|
}
|
|
13209
13850
|
const ancestryObjectToSave = {
|
|
13210
13851
|
ancestry_id: isEditMode && currentAncestryId ? currentAncestryId : `${short2.generate()}`,
|
|
@@ -13287,14 +13928,20 @@ function XViewScene({
|
|
|
13287
13928
|
try {
|
|
13288
13929
|
if (isExternalSave) {
|
|
13289
13930
|
try {
|
|
13290
|
-
const remoteResponse = await get_ancestry_file(
|
|
13931
|
+
const remoteResponse = await get_ancestry_file(
|
|
13932
|
+
targetFileIdForCache,
|
|
13933
|
+
targetOwnerIdForCache
|
|
13934
|
+
);
|
|
13291
13935
|
if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
|
|
13292
13936
|
masterAncestryList = remoteResponse.data;
|
|
13293
13937
|
} else {
|
|
13294
13938
|
masterAncestryList = [];
|
|
13295
13939
|
}
|
|
13296
13940
|
} catch (fetchErr) {
|
|
13297
|
-
console.warn(
|
|
13941
|
+
console.warn(
|
|
13942
|
+
"Arquivo de destino n\xE3o existe ou erro ao buscar, criando novo:",
|
|
13943
|
+
fetchErr
|
|
13944
|
+
);
|
|
13298
13945
|
masterAncestryList = [];
|
|
13299
13946
|
}
|
|
13300
13947
|
} else {
|
|
@@ -13314,7 +13961,9 @@ function XViewScene({
|
|
|
13314
13961
|
const result = await save_view_data(finalSaveUrl, masterAncestryList);
|
|
13315
13962
|
if (result.success) {
|
|
13316
13963
|
const localList = [...ancestryDataRef.current || []];
|
|
13317
|
-
const localIndex = localList.findIndex(
|
|
13964
|
+
const localIndex = localList.findIndex(
|
|
13965
|
+
(a) => String(a.ancestry_id) === String(ancestryObjectToSave.ancestry_id)
|
|
13966
|
+
);
|
|
13318
13967
|
if (localIndex !== -1) {
|
|
13319
13968
|
localList[localIndex] = ancestryObjectToSave;
|
|
13320
13969
|
} else {
|
|
@@ -13342,11 +13991,29 @@ function XViewScene({
|
|
|
13342
13991
|
return;
|
|
13343
13992
|
}
|
|
13344
13993
|
if (!keepOpen) {
|
|
13345
|
-
setAncestryMode({
|
|
13994
|
+
setAncestryMode({
|
|
13995
|
+
isActive: false,
|
|
13996
|
+
tree: null,
|
|
13997
|
+
selectedParentId: null,
|
|
13998
|
+
isEditMode: false,
|
|
13999
|
+
currentAncestryId: null,
|
|
14000
|
+
ancestryName: "",
|
|
14001
|
+
ancestryDescription: "",
|
|
14002
|
+
ancestryDescriptionSections: [],
|
|
14003
|
+
isAddingNodes: false
|
|
14004
|
+
});
|
|
13346
14005
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13347
14006
|
}
|
|
13348
14007
|
},
|
|
13349
|
-
[
|
|
14008
|
+
[
|
|
14009
|
+
ancestryMode,
|
|
14010
|
+
ancestry_save_url,
|
|
14011
|
+
handleRenderAncestry,
|
|
14012
|
+
save_view_data,
|
|
14013
|
+
sceneConfigId,
|
|
14014
|
+
ownerId,
|
|
14015
|
+
get_ancestry_file
|
|
14016
|
+
]
|
|
13350
14017
|
);
|
|
13351
14018
|
const handleOpenAncestryRelEditor = (path, currentData) => {
|
|
13352
14019
|
setEditingAncestryRel({ visible: true, data: currentData, path });
|
|
@@ -13376,7 +14043,9 @@ function XViewScene({
|
|
|
13376
14043
|
if (ancestryToDelete && delete_file_action) {
|
|
13377
14044
|
const urls = extractFileUrlsFromProperties(ancestryToDelete);
|
|
13378
14045
|
if (urls.length > 0) {
|
|
13379
|
-
Promise.all(urls.map((url) => delete_file_action(url))).catch(
|
|
14046
|
+
Promise.all(urls.map((url) => delete_file_action(url))).catch(
|
|
14047
|
+
(err) => console.error("Erro ao deletar arquivos da ancestralidade:", err)
|
|
14048
|
+
);
|
|
13380
14049
|
}
|
|
13381
14050
|
}
|
|
13382
14051
|
if (!ancestryToDelete) {
|
|
@@ -13386,7 +14055,9 @@ function XViewScene({
|
|
|
13386
14055
|
const sourceFileId = ancestryToDelete._source_file_id;
|
|
13387
14056
|
const sourceOwnerId = ancestryToDelete._source_owner_id;
|
|
13388
14057
|
if (!sourceFileId || !sourceOwnerId) {
|
|
13389
|
-
alert(
|
|
14058
|
+
alert(
|
|
14059
|
+
"N\xE3o foi poss\xEDvel identificar o arquivo de origem desta ancestralidade."
|
|
14060
|
+
);
|
|
13390
14061
|
return;
|
|
13391
14062
|
}
|
|
13392
14063
|
const finalSaveUrl = `x_view_ancestry/${sourceOwnerId}/${sourceFileId}`;
|
|
@@ -13394,13 +14065,18 @@ function XViewScene({
|
|
|
13394
14065
|
(anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
|
|
13395
14066
|
);
|
|
13396
14067
|
try {
|
|
13397
|
-
const result = await save_view_data(
|
|
14068
|
+
const result = await save_view_data(
|
|
14069
|
+
finalSaveUrl,
|
|
14070
|
+
updatedAncestriesForFile
|
|
14071
|
+
);
|
|
13398
14072
|
if (result.success) {
|
|
13399
14073
|
ancestryDataRef.current = (ancestryDataRef.current || []).filter(
|
|
13400
14074
|
(ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
|
|
13401
14075
|
);
|
|
13402
14076
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
13403
|
-
const renderIndex = renderedAncestries.findIndex(
|
|
14077
|
+
const renderIndex = renderedAncestries.findIndex(
|
|
14078
|
+
(a) => String(a.id) === String(ancestryIdToDelete)
|
|
14079
|
+
);
|
|
13404
14080
|
if (renderIndex !== -1) {
|
|
13405
14081
|
const toRemove = renderedAncestries[renderIndex];
|
|
13406
14082
|
toRemove.lines.forEach((line) => {
|
|
@@ -13409,18 +14085,29 @@ function XViewScene({
|
|
|
13409
14085
|
if (line.material) line.material.dispose();
|
|
13410
14086
|
});
|
|
13411
14087
|
renderedAncestries.splice(renderIndex, 1);
|
|
13412
|
-
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
14088
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
14089
|
+
(a) => a.lines
|
|
14090
|
+
);
|
|
13413
14091
|
}
|
|
13414
14092
|
setSceneVersion((v) => v + 1);
|
|
13415
14093
|
} else {
|
|
13416
|
-
throw new Error(
|
|
14094
|
+
throw new Error(
|
|
14095
|
+
result.error || "Ocorreu um erro desconhecido ao excluir."
|
|
14096
|
+
);
|
|
13417
14097
|
}
|
|
13418
14098
|
} catch (error) {
|
|
13419
14099
|
console.error("Falha ao excluir a ancestralidade:", error);
|
|
13420
14100
|
alert(`Erro ao excluir a ancestralidade: ${error.message}`);
|
|
13421
14101
|
return;
|
|
13422
14102
|
}
|
|
13423
|
-
setAncestryMode({
|
|
14103
|
+
setAncestryMode({
|
|
14104
|
+
isActive: false,
|
|
14105
|
+
tree: null,
|
|
14106
|
+
selectedParentId: null,
|
|
14107
|
+
isEditMode: false,
|
|
14108
|
+
currentAncestryId: null,
|
|
14109
|
+
ancestryName: ""
|
|
14110
|
+
});
|
|
13424
14111
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13425
14112
|
},
|
|
13426
14113
|
[save_view_data, delete_file_action]
|
|
@@ -13428,24 +14115,38 @@ function XViewScene({
|
|
|
13428
14115
|
const handleOpenAncestryBoard = useCallback4(() => {
|
|
13429
14116
|
setIsAncestryBoardOpen(true);
|
|
13430
14117
|
}, []);
|
|
13431
|
-
const handleSelectAncestryFromBoard = useCallback4(
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
14118
|
+
const handleSelectAncestryFromBoard = useCallback4(
|
|
14119
|
+
(ancestry) => {
|
|
14120
|
+
setIsAncestryBoardOpen(false);
|
|
14121
|
+
setIsSidebarOpen(false);
|
|
14122
|
+
handleStartReadingAncestry(ancestry);
|
|
14123
|
+
},
|
|
14124
|
+
[handleStartReadingAncestry]
|
|
14125
|
+
);
|
|
14126
|
+
const handleSaveAncestryBoard = useCallback4(
|
|
14127
|
+
async (groups) => {
|
|
14128
|
+
if (!sceneConfigId || !viewParams || !session) return;
|
|
14129
|
+
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
14130
|
+
await save_ancestry_board_action(
|
|
14131
|
+
sceneConfigId,
|
|
14132
|
+
sceneType,
|
|
14133
|
+
groups,
|
|
14134
|
+
session,
|
|
14135
|
+
ownerId
|
|
14136
|
+
);
|
|
14137
|
+
},
|
|
14138
|
+
[sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]
|
|
14139
|
+
);
|
|
13441
14140
|
const existingNodeTypes = useMemo12(() => {
|
|
13442
14141
|
if (!parentDataRef.current) {
|
|
13443
14142
|
return [];
|
|
13444
14143
|
}
|
|
13445
|
-
const allTypes = Object.values(parentDataRef.current).flatMap(
|
|
13446
|
-
|
|
13447
|
-
|
|
13448
|
-
|
|
14144
|
+
const allTypes = Object.values(parentDataRef.current).flatMap(
|
|
14145
|
+
(fileData) => fileData.nodes.flatMap((node) => {
|
|
14146
|
+
if (Array.isArray(node.type)) return node.type;
|
|
14147
|
+
return [node.type];
|
|
14148
|
+
})
|
|
14149
|
+
).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
|
|
13449
14150
|
return [...new Set(allTypes)];
|
|
13450
14151
|
}, [parentDataRef.current, sceneVersion]);
|
|
13451
14152
|
const searchableDbNodes = useMemo12(() => {
|
|
@@ -13459,7 +14160,10 @@ function XViewScene({
|
|
|
13459
14160
|
}, [parentDataRef.current, sceneVersion]);
|
|
13460
14161
|
const handleAddExistingNode = useCallback4(
|
|
13461
14162
|
(nodeId) => {
|
|
13462
|
-
return userActionHandlers.handleAddExistingNodeById(
|
|
14163
|
+
return userActionHandlers.handleAddExistingNodeById(
|
|
14164
|
+
actionHandlerContext,
|
|
14165
|
+
nodeId
|
|
14166
|
+
);
|
|
13463
14167
|
},
|
|
13464
14168
|
[actionHandlerContext]
|
|
13465
14169
|
);
|
|
@@ -13467,7 +14171,9 @@ function XViewScene({
|
|
|
13467
14171
|
var _a2, _b2, _c2;
|
|
13468
14172
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
13469
14173
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
13470
|
-
console.warn(
|
|
14174
|
+
console.warn(
|
|
14175
|
+
"N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente."
|
|
14176
|
+
);
|
|
13471
14177
|
return;
|
|
13472
14178
|
}
|
|
13473
14179
|
if (!save_view_data) return;
|
|
@@ -13504,48 +14210,68 @@ function XViewScene({
|
|
|
13504
14210
|
}, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
|
|
13505
14211
|
const allAvailableNodes = useMemo12(() => {
|
|
13506
14212
|
if (!parentDataRef.current) return [];
|
|
13507
|
-
return Object.values(parentDataRef.current).flatMap(
|
|
14213
|
+
return Object.values(parentDataRef.current).flatMap(
|
|
14214
|
+
(fileData) => fileData.nodes || []
|
|
14215
|
+
);
|
|
13508
14216
|
}, [sceneVersion, isInitialized]);
|
|
13509
14217
|
const allAvailableAncestries = useMemo12(() => {
|
|
13510
14218
|
return ancestryDataRef.current || [];
|
|
13511
14219
|
}, [sceneVersion, isInitialized]);
|
|
13512
|
-
const handleOpenReference = useCallback4(
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
14220
|
+
const handleOpenReference = useCallback4(
|
|
14221
|
+
(referenceData) => {
|
|
14222
|
+
const { type, id } = referenceData;
|
|
14223
|
+
if (type === "node") {
|
|
14224
|
+
const targetNode = allAvailableNodes.find(
|
|
14225
|
+
(n) => String(n.id) === String(id)
|
|
14226
|
+
);
|
|
14227
|
+
if (targetNode) {
|
|
14228
|
+
setAncestryLinkDetails(null);
|
|
14229
|
+
setDetailsLink(null);
|
|
14230
|
+
setDetailsNode(targetNode);
|
|
14231
|
+
const sceneMesh = stateRef.current.nodeObjects[String(id)];
|
|
14232
|
+
if (sceneMesh) {
|
|
14233
|
+
tweenToTarget(sceneMesh);
|
|
14234
|
+
}
|
|
14235
|
+
} else {
|
|
14236
|
+
alert("Node original n\xE3o encontrado neste contexto.");
|
|
14237
|
+
}
|
|
14238
|
+
} else if (type === "ancestry") {
|
|
14239
|
+
const targetAncestry = allAvailableAncestries.find(
|
|
14240
|
+
(a) => String(a.ancestry_id) === String(id)
|
|
14241
|
+
);
|
|
14242
|
+
if (targetAncestry) {
|
|
14243
|
+
setDetailsNode(null);
|
|
14244
|
+
setDetailsLink(null);
|
|
14245
|
+
setAncestryLinkDetails(null);
|
|
14246
|
+
handleEditAncestry(targetAncestry);
|
|
14247
|
+
} else {
|
|
14248
|
+
alert("Ancestralidade original n\xE3o encontrada neste contexto.");
|
|
13523
14249
|
}
|
|
13524
|
-
} else {
|
|
13525
|
-
alert("Node original n\xE3o encontrado neste contexto.");
|
|
13526
|
-
}
|
|
13527
|
-
} else if (type === "ancestry") {
|
|
13528
|
-
const targetAncestry = allAvailableAncestries.find((a) => String(a.ancestry_id) === String(id));
|
|
13529
|
-
if (targetAncestry) {
|
|
13530
|
-
setDetailsNode(null);
|
|
13531
|
-
setDetailsLink(null);
|
|
13532
|
-
setAncestryLinkDetails(null);
|
|
13533
|
-
handleEditAncestry(targetAncestry);
|
|
13534
|
-
} else {
|
|
13535
|
-
alert("Ancestralidade original n\xE3o encontrada neste contexto.");
|
|
13536
14250
|
}
|
|
13537
|
-
}
|
|
13538
|
-
|
|
14251
|
+
},
|
|
14252
|
+
[
|
|
14253
|
+
allAvailableNodes,
|
|
14254
|
+
allAvailableAncestries,
|
|
14255
|
+
handleEditAncestry,
|
|
14256
|
+
tweenToTarget
|
|
14257
|
+
]
|
|
14258
|
+
);
|
|
13539
14259
|
const handleToggleAncestryAddMode = useCallback4(() => {
|
|
13540
|
-
setAncestryMode((prev) => ({
|
|
14260
|
+
setAncestryMode((prev) => ({
|
|
14261
|
+
...prev,
|
|
14262
|
+
isAddingNodes: !prev.isAddingNodes
|
|
14263
|
+
}));
|
|
13541
14264
|
}, []);
|
|
13542
|
-
const handleFocusNode = useCallback4(
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
14265
|
+
const handleFocusNode = useCallback4(
|
|
14266
|
+
(nodeData) => {
|
|
14267
|
+
if (!nodeData) return;
|
|
14268
|
+
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
14269
|
+
if (nodeMesh) {
|
|
14270
|
+
tweenToTarget(nodeMesh, 1.2);
|
|
14271
|
+
}
|
|
14272
|
+
},
|
|
14273
|
+
[tweenToTarget]
|
|
14274
|
+
);
|
|
13549
14275
|
const availableDatasets = useMemo12(() => {
|
|
13550
14276
|
if (!sceneDataRef.current || !parentDataRef.current) return [];
|
|
13551
14277
|
return sceneDataRef.current.parent_dbs.map((db) => {
|
|
@@ -13556,7 +14282,9 @@ function XViewScene({
|
|
|
13556
14282
|
};
|
|
13557
14283
|
});
|
|
13558
14284
|
}, [sceneVersion, isInitialized]);
|
|
13559
|
-
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
|
|
14285
|
+
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
|
|
14286
|
+
String(creationMode.sourceNodeData.id)
|
|
14287
|
+
)) == null ? void 0 : _b.parentFileId : null;
|
|
13560
14288
|
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
13561
14289
|
useEffect22(() => {
|
|
13562
14290
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
@@ -13571,11 +14299,19 @@ function XViewScene({
|
|
|
13571
14299
|
setHasFocusedInitial(true);
|
|
13572
14300
|
}
|
|
13573
14301
|
}
|
|
13574
|
-
}, [
|
|
14302
|
+
}, [
|
|
14303
|
+
isInitialized,
|
|
14304
|
+
sceneVersion,
|
|
14305
|
+
focusNodeId,
|
|
14306
|
+
hasFocusedInitial,
|
|
14307
|
+
tweenToTarget
|
|
14308
|
+
]);
|
|
13575
14309
|
useEffect22(() => {
|
|
13576
14310
|
if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
|
|
13577
14311
|
const ancestries = ancestryDataRef.current || [];
|
|
13578
|
-
const targetAncestry = ancestries.find(
|
|
14312
|
+
const targetAncestry = ancestries.find(
|
|
14313
|
+
(a) => String(a.ancestry_id) === String(focusAncestryId)
|
|
14314
|
+
);
|
|
13579
14315
|
if (targetAncestry) {
|
|
13580
14316
|
setTimeout(() => {
|
|
13581
14317
|
handleStartReadingAncestry(targetAncestry);
|
|
@@ -13585,18 +14321,38 @@ function XViewScene({
|
|
|
13585
14321
|
setHasOpenedInitialAncestry(true);
|
|
13586
14322
|
}
|
|
13587
14323
|
}
|
|
13588
|
-
}, [
|
|
14324
|
+
}, [
|
|
14325
|
+
isInitialized,
|
|
14326
|
+
sceneVersion,
|
|
14327
|
+
focusAncestryId,
|
|
14328
|
+
hasOpenedInitialAncestry,
|
|
14329
|
+
handleStartReadingAncestry
|
|
14330
|
+
]);
|
|
13589
14331
|
useEffect22(() => {
|
|
13590
14332
|
function handleKeyDown(event) {
|
|
13591
14333
|
var _a2, _b2, _c2;
|
|
13592
14334
|
const context = actionHandlerContext;
|
|
13593
14335
|
if (event.key === "Escape") {
|
|
13594
|
-
if (stateRef.current.connection.isActive)
|
|
13595
|
-
|
|
13596
|
-
if (stateRef.current.
|
|
13597
|
-
|
|
14336
|
+
if (stateRef.current.connection.isActive)
|
|
14337
|
+
userActionHandlers.handleCancelConnection(context);
|
|
14338
|
+
if (stateRef.current.relink.isActive)
|
|
14339
|
+
userActionHandlers.handleCancelRelink(context);
|
|
14340
|
+
if (stateRef.current.creation.isActive)
|
|
14341
|
+
userActionHandlers.handleCancelCreation(context);
|
|
14342
|
+
if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive)
|
|
14343
|
+
userActionHandlers.handleCancelVersioning(context);
|
|
13598
14344
|
if (stateRef.current.ancestry.isActive) {
|
|
13599
|
-
setAncestryMode({
|
|
14345
|
+
setAncestryMode({
|
|
14346
|
+
isActive: false,
|
|
14347
|
+
tree: null,
|
|
14348
|
+
selectedParentId: null,
|
|
14349
|
+
isEditMode: false,
|
|
14350
|
+
currentAncestryId: null,
|
|
14351
|
+
ancestryName: "",
|
|
14352
|
+
ancestryDescription: "",
|
|
14353
|
+
ancestryDescriptionSections: [],
|
|
14354
|
+
isAddingNodes: false
|
|
14355
|
+
});
|
|
13600
14356
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13601
14357
|
}
|
|
13602
14358
|
if (questMode.isActive) {
|
|
@@ -13605,7 +14361,9 @@ function XViewScene({
|
|
|
13605
14361
|
if (stateRef.current.selectedNodes.size > 0) {
|
|
13606
14362
|
stateRef.current.selectedNodes.clear();
|
|
13607
14363
|
}
|
|
13608
|
-
setContextMenu(
|
|
14364
|
+
setContextMenu(
|
|
14365
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
14366
|
+
);
|
|
13609
14367
|
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
13610
14368
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
13611
14369
|
}
|
|
@@ -13624,7 +14382,9 @@ function XViewScene({
|
|
|
13624
14382
|
let attempts = 0;
|
|
13625
14383
|
const MIN_CLEARANCE = 15;
|
|
13626
14384
|
while (isOccupied && attempts < 30) {
|
|
13627
|
-
isOccupied = existingNodes.some(
|
|
14385
|
+
isOccupied = existingNodes.some(
|
|
14386
|
+
(mesh) => mesh.position.distanceTo(ghostPosition) < MIN_CLEARANCE
|
|
14387
|
+
);
|
|
13628
14388
|
if (isOccupied) {
|
|
13629
14389
|
ghostPosition.x = controls.target.x + Math.cos(angle) * radius;
|
|
13630
14390
|
ghostPosition.y = controls.target.y + (Math.random() - 0.5) * 8;
|
|
@@ -13643,7 +14403,11 @@ function XViewScene({
|
|
|
13643
14403
|
intensity: 0,
|
|
13644
14404
|
type: ["quest"]
|
|
13645
14405
|
};
|
|
13646
|
-
const ghostNode = createNodeMesh(
|
|
14406
|
+
const ghostNode = createNodeMesh(
|
|
14407
|
+
ghostData,
|
|
14408
|
+
ghostPosition,
|
|
14409
|
+
glowTexture
|
|
14410
|
+
);
|
|
13647
14411
|
ghostNode.traverse((child) => {
|
|
13648
14412
|
if (child.isMesh) {
|
|
13649
14413
|
child.material.transparent = true;
|
|
@@ -13690,13 +14454,49 @@ function XViewScene({
|
|
|
13690
14454
|
return /* @__PURE__ */ React25.createElement(LoadingScreen, null);
|
|
13691
14455
|
}
|
|
13692
14456
|
if (permissionStatus === "denied") {
|
|
13693
|
-
return /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React25.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React25.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React25.createElement(
|
|
14457
|
+
return /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React25.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React25.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React25.createElement(
|
|
14458
|
+
"svg",
|
|
14459
|
+
{
|
|
14460
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14461
|
+
fill: "none",
|
|
14462
|
+
viewBox: "0 0 24 24",
|
|
14463
|
+
strokeWidth: 1.5,
|
|
14464
|
+
stroke: "currentColor",
|
|
14465
|
+
className: "w-16 h-16 mx-auto"
|
|
14466
|
+
},
|
|
14467
|
+
/* @__PURE__ */ React25.createElement(
|
|
14468
|
+
"path",
|
|
14469
|
+
{
|
|
14470
|
+
strokeLinecap: "round",
|
|
14471
|
+
strokeLinejoin: "round",
|
|
14472
|
+
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"
|
|
14473
|
+
}
|
|
14474
|
+
)
|
|
14475
|
+
)), /* @__PURE__ */ React25.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React25.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React25.createElement(
|
|
13694
14476
|
"button",
|
|
13695
14477
|
{
|
|
13696
14478
|
onClick: () => router.push("/dashboard/scenes"),
|
|
13697
14479
|
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"
|
|
13698
14480
|
},
|
|
13699
|
-
/* @__PURE__ */ React25.createElement(
|
|
14481
|
+
/* @__PURE__ */ React25.createElement(
|
|
14482
|
+
"svg",
|
|
14483
|
+
{
|
|
14484
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14485
|
+
fill: "none",
|
|
14486
|
+
viewBox: "0 0 24 24",
|
|
14487
|
+
strokeWidth: 2,
|
|
14488
|
+
stroke: "currentColor",
|
|
14489
|
+
className: "w-5 h-5"
|
|
14490
|
+
},
|
|
14491
|
+
/* @__PURE__ */ React25.createElement(
|
|
14492
|
+
"path",
|
|
14493
|
+
{
|
|
14494
|
+
strokeLinecap: "round",
|
|
14495
|
+
strokeLinejoin: "round",
|
|
14496
|
+
d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"
|
|
14497
|
+
}
|
|
14498
|
+
)
|
|
14499
|
+
),
|
|
13700
14500
|
"Voltar para Scenes"
|
|
13701
14501
|
)));
|
|
13702
14502
|
}
|
|
@@ -13743,7 +14543,14 @@ function XViewScene({
|
|
|
13743
14543
|
onImageChange: handleGhostNodeImageChange,
|
|
13744
14544
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13745
14545
|
onMentionClick: handleAddExistingNode,
|
|
13746
|
-
style: {
|
|
14546
|
+
style: {
|
|
14547
|
+
position: "absolute",
|
|
14548
|
+
left: `${formPosition.left}px`,
|
|
14549
|
+
top: `${formPosition.top}px`,
|
|
14550
|
+
opacity: formPosition.opacity,
|
|
14551
|
+
zIndex: 20,
|
|
14552
|
+
transition: "opacity 200ms ease-out"
|
|
14553
|
+
},
|
|
13747
14554
|
refEl: formRef,
|
|
13748
14555
|
existingTypes: existingNodeTypes,
|
|
13749
14556
|
initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
|
|
@@ -13767,7 +14574,14 @@ function XViewScene({
|
|
|
13767
14574
|
onImageChange: handleGhostNodeImageChange,
|
|
13768
14575
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13769
14576
|
onMentionClick: handleAddExistingNode,
|
|
13770
|
-
style: {
|
|
14577
|
+
style: {
|
|
14578
|
+
position: "absolute",
|
|
14579
|
+
left: `${formPosition.left}px`,
|
|
14580
|
+
top: `${formPosition.top}px`,
|
|
14581
|
+
opacity: formPosition.opacity,
|
|
14582
|
+
zIndex: 20,
|
|
14583
|
+
transition: "opacity 200ms ease-out"
|
|
14584
|
+
},
|
|
13771
14585
|
refEl: formRef,
|
|
13772
14586
|
fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
|
|
13773
14587
|
fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
|
|
@@ -13784,7 +14598,13 @@ function XViewScene({
|
|
|
13784
14598
|
onNameChange: handleGhostNodeNameChange,
|
|
13785
14599
|
onColorChange: handleGhostNodeColorChange,
|
|
13786
14600
|
onSizeChange: handleGhostNodeSizeChange,
|
|
13787
|
-
style: {
|
|
14601
|
+
style: {
|
|
14602
|
+
position: "absolute",
|
|
14603
|
+
left: `16px`,
|
|
14604
|
+
top: `16px`,
|
|
14605
|
+
zIndex: 20,
|
|
14606
|
+
transition: "opacity 200ms ease-out"
|
|
14607
|
+
},
|
|
13788
14608
|
refEl: formRef,
|
|
13789
14609
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13790
14610
|
onMentionClick: handleAddExistingNode,
|
|
@@ -13799,7 +14619,14 @@ function XViewScene({
|
|
|
13799
14619
|
"div",
|
|
13800
14620
|
{
|
|
13801
14621
|
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"}`,
|
|
13802
|
-
style: {
|
|
14622
|
+
style: {
|
|
14623
|
+
top: 16,
|
|
14624
|
+
right: 16,
|
|
14625
|
+
zIndex: 1100,
|
|
14626
|
+
maxHeight: "calc(100vh - 32px)",
|
|
14627
|
+
width: `${readModeWidth}px`,
|
|
14628
|
+
maxWidth: "92vw"
|
|
14629
|
+
}
|
|
13803
14630
|
},
|
|
13804
14631
|
/* @__PURE__ */ React25.createElement(
|
|
13805
14632
|
"div",
|
|
@@ -13857,7 +14684,16 @@ function XViewScene({
|
|
|
13857
14684
|
onSave: handleSaveAncestry,
|
|
13858
14685
|
onEditRelationship: handleOpenAncestryRelEditor,
|
|
13859
14686
|
onClose: () => {
|
|
13860
|
-
setAncestryMode({
|
|
14687
|
+
setAncestryMode({
|
|
14688
|
+
isActive: false,
|
|
14689
|
+
tree: null,
|
|
14690
|
+
selectedParentId: null,
|
|
14691
|
+
isEditMode: false,
|
|
14692
|
+
currentAncestryId: null,
|
|
14693
|
+
ancestryName: "",
|
|
14694
|
+
ancestryDescription: "",
|
|
14695
|
+
isAddingNodes: false
|
|
14696
|
+
});
|
|
13861
14697
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13862
14698
|
},
|
|
13863
14699
|
availableNodes: allAvailableNodes,
|
|
@@ -13922,7 +14758,12 @@ function XViewScene({
|
|
|
13922
14758
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13923
14759
|
existingTypes: existingNodeTypes,
|
|
13924
14760
|
onImageChange: (useImage, url, currentColorOverride) => {
|
|
13925
|
-
const updatedNode = {
|
|
14761
|
+
const updatedNode = {
|
|
14762
|
+
...detailsNode,
|
|
14763
|
+
useImageAsTexture: useImage,
|
|
14764
|
+
textureImageUrl: url,
|
|
14765
|
+
color: currentColorOverride || detailsNode.color
|
|
14766
|
+
};
|
|
13926
14767
|
updateExistingNodeVisuals(stateRef.current, updatedNode);
|
|
13927
14768
|
setDetailsNode(updatedNode);
|
|
13928
14769
|
},
|
|
@@ -13996,7 +14837,9 @@ function XViewScene({
|
|
|
13996
14837
|
parentData: parentDataRef.current,
|
|
13997
14838
|
sceneData: sceneDataRef.current,
|
|
13998
14839
|
ancestryData: ancestryDataRef.current,
|
|
13999
|
-
onClose: () => setContextMenu(
|
|
14840
|
+
onClose: () => setContextMenu(
|
|
14841
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
14842
|
+
),
|
|
14000
14843
|
onStartCreation: (data) => userActionHandlers.handleStartCreation(actionHandlerContext, data),
|
|
14001
14844
|
onStartConnection: (data) => userActionHandlers.handleStartConnection(actionHandlerContext, data),
|
|
14002
14845
|
onStartVersioning: handleStartVersioning,
|
|
@@ -14004,7 +14847,11 @@ function XViewScene({
|
|
|
14004
14847
|
onDeleteNode: (data) => userActionHandlers.handleDeleteNode(actionHandlerContext, data),
|
|
14005
14848
|
onDismissNode: (data) => userActionHandlers.handleDismissNode(actionHandlerContext, data),
|
|
14006
14849
|
onDismissOtherNodes: (data) => userActionHandlers.handleDismissOtherNodes(actionHandlerContext, data),
|
|
14007
|
-
onExpandConnections: (sourceNode, links) => userActionHandlers.handleExpandConnections(
|
|
14850
|
+
onExpandConnections: (sourceNode, links) => userActionHandlers.handleExpandConnections(
|
|
14851
|
+
actionHandlerContext,
|
|
14852
|
+
sourceNode,
|
|
14853
|
+
links
|
|
14854
|
+
),
|
|
14008
14855
|
onRenderAncestry: handleStartReadingAncestry,
|
|
14009
14856
|
onEditAncestry: handleEditAncestry,
|
|
14010
14857
|
onDeleteAncestry: (ancestryId) => handleDeleteAncestry(ancestryId),
|
|
@@ -14017,9 +14864,18 @@ function XViewScene({
|
|
|
14017
14864
|
data: multiContextMenu,
|
|
14018
14865
|
userRole: userPermissionRole,
|
|
14019
14866
|
onClose: () => setMultiContextMenu((prev) => ({ ...prev, visible: false })),
|
|
14020
|
-
onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(
|
|
14021
|
-
|
|
14022
|
-
|
|
14867
|
+
onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(
|
|
14868
|
+
actionHandlerContext,
|
|
14869
|
+
ids
|
|
14870
|
+
),
|
|
14871
|
+
onDismissOtherNodes: (ids) => userActionHandlers.handleDismissOtherMultipleNodes(
|
|
14872
|
+
actionHandlerContext,
|
|
14873
|
+
ids
|
|
14874
|
+
),
|
|
14875
|
+
onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(
|
|
14876
|
+
actionHandlerContext,
|
|
14877
|
+
ids
|
|
14878
|
+
)
|
|
14023
14879
|
}
|
|
14024
14880
|
),
|
|
14025
14881
|
/* @__PURE__ */ React25.createElement(
|
|
@@ -14040,7 +14896,13 @@ function XViewScene({
|
|
|
14040
14896
|
onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
|
|
14041
14897
|
}
|
|
14042
14898
|
),
|
|
14043
|
-
/* @__PURE__ */ React25.createElement(
|
|
14899
|
+
/* @__PURE__ */ React25.createElement(
|
|
14900
|
+
ImageViewer,
|
|
14901
|
+
{
|
|
14902
|
+
data: imageViewer,
|
|
14903
|
+
onClose: () => setImageViewer({ ...imageViewer, visible: false })
|
|
14904
|
+
}
|
|
14905
|
+
),
|
|
14044
14906
|
/* @__PURE__ */ React25.createElement(
|
|
14045
14907
|
AncestryBoard,
|
|
14046
14908
|
{
|