@lv-x-software-house/x_view 1.2.4-dev.17 → 1.2.4-dev.19
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 +106 -24
- package/dist/index.mjs +106 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7967,7 +7967,11 @@ function InSceneQuestForm({
|
|
|
7967
7967
|
availableNodes = [],
|
|
7968
7968
|
availableAncestries = [],
|
|
7969
7969
|
onMentionClick,
|
|
7970
|
-
onUploadFile
|
|
7970
|
+
onUploadFile,
|
|
7971
|
+
// NOVAS PROPS PARA O GHOST NODE
|
|
7972
|
+
onNameChange,
|
|
7973
|
+
onColorChange,
|
|
7974
|
+
onSizeChange
|
|
7971
7975
|
}) {
|
|
7972
7976
|
const [name, setName] = (0, import_react16.useState)("");
|
|
7973
7977
|
const [types, setTypes] = (0, import_react16.useState)(["quest"]);
|
|
@@ -8079,12 +8083,26 @@ function InSceneQuestForm({
|
|
|
8079
8083
|
onClick: () => {
|
|
8080
8084
|
setStatus(s);
|
|
8081
8085
|
setIsStatusDropdownOpen(false);
|
|
8086
|
+
onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS[s]);
|
|
8082
8087
|
},
|
|
8083
8088
|
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
8084
8089
|
},
|
|
8085
8090
|
/* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS[s] } }),
|
|
8086
8091
|
s
|
|
8087
|
-
)))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ import_react16.default.createElement(
|
|
8092
|
+
)))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ import_react16.default.createElement(
|
|
8093
|
+
"input",
|
|
8094
|
+
{
|
|
8095
|
+
required: true,
|
|
8096
|
+
type: "text",
|
|
8097
|
+
placeholder: "Ex.: Refatorar M\xF3dulo X",
|
|
8098
|
+
value: name,
|
|
8099
|
+
onChange: (e) => {
|
|
8100
|
+
setName(e.target.value);
|
|
8101
|
+
onNameChange == null ? void 0 : onNameChange(e.target.value);
|
|
8102
|
+
},
|
|
8103
|
+
className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
|
|
8104
|
+
}
|
|
8105
|
+
)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ import_react16.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiX, { size: 12 })))), /* @__PURE__ */ import_react16.default.createElement(
|
|
8088
8106
|
"input",
|
|
8089
8107
|
{
|
|
8090
8108
|
type: "text",
|
|
@@ -8107,7 +8125,20 @@ function InSceneQuestForm({
|
|
|
8107
8125
|
onMentionClick,
|
|
8108
8126
|
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
8109
8127
|
}
|
|
8110
|
-
), /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiEdit2, { size: 14 }))), !description && /* @__PURE__ */ import_react16.default.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ import_react16.default.createElement(
|
|
8128
|
+
), /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiEdit2, { size: 14 }))), !description && /* @__PURE__ */ import_react16.default.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ import_react16.default.createElement(
|
|
8129
|
+
"button",
|
|
8130
|
+
{
|
|
8131
|
+
key: s,
|
|
8132
|
+
type: "button",
|
|
8133
|
+
onClick: () => {
|
|
8134
|
+
setSize(s);
|
|
8135
|
+
onSizeChange == null ? void 0 : onSizeChange(s);
|
|
8136
|
+
},
|
|
8137
|
+
className: "flex items-center gap-2 group cursor-pointer focus:outline-none"
|
|
8138
|
+
},
|
|
8139
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: `w-4 h-4 rounded-[4px] border flex items-center justify-center transition-all duration-200 ${size === s ? "bg-indigo-500 border-indigo-500" : "border-slate-600 bg-transparent group-hover:border-slate-500"}` }, size === s && /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiCheck, { size: 12, className: "text-white" })),
|
|
8140
|
+
/* @__PURE__ */ import_react16.default.createElement("span", { className: `text-sm capitalize transition-colors ${size === s ? "text-white font-medium" : "text-slate-400 group-hover:text-slate-300"}` }, s)
|
|
8141
|
+
)))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react16.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiPlus, { size: 14 }), " Adicionar")), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ import_react16.default.createElement(
|
|
8111
8142
|
CustomPropertyDisplay,
|
|
8112
8143
|
{
|
|
8113
8144
|
key: prop.id,
|
|
@@ -11603,6 +11634,26 @@ function XViewScene({
|
|
|
11603
11634
|
const handleStartVersioning = (nodeData) => {
|
|
11604
11635
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
11605
11636
|
};
|
|
11637
|
+
const handleCancelQuest = (0, import_react25.useCallback)(() => {
|
|
11638
|
+
const { graphGroup, ghostElements } = stateRef.current;
|
|
11639
|
+
if (ghostElements.node && graphGroup) {
|
|
11640
|
+
if (ghostElements.node.userData.labelObject) {
|
|
11641
|
+
graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
11642
|
+
if (ghostElements.node.userData.labelObject.material.map) ghostElements.node.userData.labelObject.material.map.dispose();
|
|
11643
|
+
ghostElements.node.userData.labelObject.material.dispose();
|
|
11644
|
+
}
|
|
11645
|
+
graphGroup.remove(ghostElements.node);
|
|
11646
|
+
ghostElements.node.traverse((child) => {
|
|
11647
|
+
if (child.material) {
|
|
11648
|
+
if (Array.isArray(child.material)) child.material.forEach((m) => m.dispose());
|
|
11649
|
+
else child.material.dispose();
|
|
11650
|
+
}
|
|
11651
|
+
if (child.geometry) child.geometry.dispose();
|
|
11652
|
+
});
|
|
11653
|
+
}
|
|
11654
|
+
stateRef.current.ghostElements = { node: null, line: null, aura: null };
|
|
11655
|
+
setQuestMode({ isActive: false });
|
|
11656
|
+
}, []);
|
|
11606
11657
|
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
11607
11658
|
const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
|
|
11608
11659
|
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
@@ -11619,9 +11670,7 @@ function XViewScene({
|
|
|
11619
11670
|
const sceneFileData = {
|
|
11620
11671
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11621
11672
|
nodes: sceneDataRef2.current.nodes,
|
|
11622
|
-
// <-- Mantém o cenário inicial inalterado
|
|
11623
11673
|
links: sceneDataRef2.current.links,
|
|
11624
|
-
// <-- Mantém o cenário inicial inalterado
|
|
11625
11674
|
quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
|
|
11626
11675
|
quest_links: graphDataRef.current[sceneConfigId2].links
|
|
11627
11676
|
};
|
|
@@ -11632,9 +11681,13 @@ function XViewScene({
|
|
|
11632
11681
|
ownerId: ownerId2,
|
|
11633
11682
|
datasetName: "Quests Internas (View)"
|
|
11634
11683
|
});
|
|
11635
|
-
const
|
|
11636
|
-
const
|
|
11637
|
-
|
|
11684
|
+
const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
|
|
11685
|
+
const { graphGroup, ghostElements } = stateRef2.current;
|
|
11686
|
+
if (ghostElements.node && graphGroup) {
|
|
11687
|
+
if (ghostElements.node.userData.labelObject) graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
11688
|
+
graphGroup.remove(ghostElements.node);
|
|
11689
|
+
}
|
|
11690
|
+
stateRef2.current.ghostElements = { node: null, line: null, aura: null };
|
|
11638
11691
|
addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
|
|
11639
11692
|
context.tweenToTarget(finalPosition, 1.2);
|
|
11640
11693
|
setters.setQuestMode({ isActive: false });
|
|
@@ -11672,12 +11725,9 @@ function XViewScene({
|
|
|
11672
11725
|
const viewFilePayload = {
|
|
11673
11726
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11674
11727
|
nodes: sceneDataRef2.current.nodes,
|
|
11675
|
-
// <-- Usa o estado original intocado
|
|
11676
11728
|
links: sceneDataRef2.current.links,
|
|
11677
|
-
// <-- Usa o estado original intocado
|
|
11678
11729
|
quest_nodes: specificParentData.nodes,
|
|
11679
11730
|
quest_links: specificParentData.links
|
|
11680
|
-
// Salva a conexão aqui!
|
|
11681
11731
|
};
|
|
11682
11732
|
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
11683
11733
|
} else {
|
|
@@ -13085,7 +13135,7 @@ function XViewScene({
|
|
|
13085
13135
|
}, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
|
|
13086
13136
|
(0, import_react25.useEffect)(() => {
|
|
13087
13137
|
function handleKeyDown(event) {
|
|
13088
|
-
var _a2, _b2, _c2
|
|
13138
|
+
var _a2, _b2, _c2;
|
|
13089
13139
|
const context = actionHandlerContext;
|
|
13090
13140
|
if (event.key === "Escape") {
|
|
13091
13141
|
if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
|
|
@@ -13096,7 +13146,9 @@ function XViewScene({
|
|
|
13096
13146
|
setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
13097
13147
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13098
13148
|
}
|
|
13099
|
-
if (
|
|
13149
|
+
if (questMode.isActive) {
|
|
13150
|
+
handleCancelQuest();
|
|
13151
|
+
}
|
|
13100
13152
|
if (stateRef.current.selectedNodes.size > 0) {
|
|
13101
13153
|
stateRef.current.selectedNodes.clear();
|
|
13102
13154
|
}
|
|
@@ -13105,16 +13157,42 @@ function XViewScene({
|
|
|
13105
13157
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
13106
13158
|
}
|
|
13107
13159
|
if (event.key.toLowerCase() === "q") {
|
|
13108
|
-
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((
|
|
13109
|
-
!detailsNode && // Condição nova
|
|
13110
|
-
!detailsLink && // Condição nova
|
|
13111
|
-
!ancestryLinkDetails && // Condição nova
|
|
13112
|
-
!imageViewer.visible && // Condição nova
|
|
13113
|
-
!editingAncestryRel.visible && // Condição nova
|
|
13114
|
-
!questMode.isActive;
|
|
13160
|
+
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
|
|
13115
13161
|
if (isUiClear) {
|
|
13116
|
-
const isView = ((
|
|
13162
|
+
const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
|
|
13117
13163
|
if (!isView) return;
|
|
13164
|
+
const { graphGroup, glowTexture, controls } = stateRef.current;
|
|
13165
|
+
if (graphGroup) {
|
|
13166
|
+
const basePosition = controls.target.clone();
|
|
13167
|
+
const offset = new THREE3.Vector3((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 5, 0);
|
|
13168
|
+
const ghostPosition = basePosition.add(offset);
|
|
13169
|
+
const ghostData = {
|
|
13170
|
+
id: "ghost_quest",
|
|
13171
|
+
name: "Nova Quest",
|
|
13172
|
+
color: "#64748b",
|
|
13173
|
+
// Cor padrão de "Backlog"
|
|
13174
|
+
size: "medium",
|
|
13175
|
+
intensity: 0,
|
|
13176
|
+
type: ["quest"]
|
|
13177
|
+
};
|
|
13178
|
+
const ghostNode = createNodeMesh(ghostData, ghostPosition, glowTexture);
|
|
13179
|
+
ghostNode.traverse((child) => {
|
|
13180
|
+
if (child.isMesh) {
|
|
13181
|
+
child.material.transparent = true;
|
|
13182
|
+
child.material.opacity = 0.75;
|
|
13183
|
+
}
|
|
13184
|
+
});
|
|
13185
|
+
graphGroup.add(ghostNode);
|
|
13186
|
+
if (ghostNode.userData.labelObject) {
|
|
13187
|
+
graphGroup.add(ghostNode.userData.labelObject);
|
|
13188
|
+
}
|
|
13189
|
+
stateRef.current.ghostElements = {
|
|
13190
|
+
node: ghostNode,
|
|
13191
|
+
line: null,
|
|
13192
|
+
// Quests não possuem linha de conexão na criação
|
|
13193
|
+
aura: ghostNode.getObjectByName("aura")
|
|
13194
|
+
};
|
|
13195
|
+
}
|
|
13118
13196
|
setQuestMode({ isActive: true });
|
|
13119
13197
|
}
|
|
13120
13198
|
}
|
|
@@ -13122,7 +13200,6 @@ function XViewScene({
|
|
|
13122
13200
|
window.addEventListener("keydown", handleKeyDown);
|
|
13123
13201
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
13124
13202
|
}, [
|
|
13125
|
-
// Dependências: sempre que um painel abrir ou fechar, o React atualiza o listener com os dados frescos
|
|
13126
13203
|
contextMenu.visible,
|
|
13127
13204
|
multiContextMenu.visible,
|
|
13128
13205
|
relationshipMenu.visible,
|
|
@@ -13137,7 +13214,9 @@ function XViewScene({
|
|
|
13137
13214
|
editingAncestryRel.visible,
|
|
13138
13215
|
questMode.isActive,
|
|
13139
13216
|
viewParams,
|
|
13140
|
-
actionHandlerContext
|
|
13217
|
+
actionHandlerContext,
|
|
13218
|
+
handleCancelQuest
|
|
13219
|
+
// <-- handleCancelQuest adicionado aqui
|
|
13141
13220
|
]);
|
|
13142
13221
|
if (isLoading || status === "loading" || permissionStatus === "loading") {
|
|
13143
13222
|
return /* @__PURE__ */ import_react25.default.createElement(LoadingScreen, null);
|
|
@@ -13233,7 +13312,10 @@ function XViewScene({
|
|
|
13233
13312
|
InSceneQuestForm,
|
|
13234
13313
|
{
|
|
13235
13314
|
onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
|
|
13236
|
-
onCancel:
|
|
13315
|
+
onCancel: handleCancelQuest,
|
|
13316
|
+
onNameChange: handleGhostNodeNameChange,
|
|
13317
|
+
onColorChange: handleGhostNodeColorChange,
|
|
13318
|
+
onSizeChange: handleGhostNodeSizeChange,
|
|
13237
13319
|
style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
13238
13320
|
refEl: formRef,
|
|
13239
13321
|
onOpenImageViewer: handleOpenImageViewer,
|
package/dist/index.mjs
CHANGED
|
@@ -7954,7 +7954,11 @@ function InSceneQuestForm({
|
|
|
7954
7954
|
availableNodes = [],
|
|
7955
7955
|
availableAncestries = [],
|
|
7956
7956
|
onMentionClick,
|
|
7957
|
-
onUploadFile
|
|
7957
|
+
onUploadFile,
|
|
7958
|
+
// NOVAS PROPS PARA O GHOST NODE
|
|
7959
|
+
onNameChange,
|
|
7960
|
+
onColorChange,
|
|
7961
|
+
onSizeChange
|
|
7958
7962
|
}) {
|
|
7959
7963
|
const [name, setName] = useState16("");
|
|
7960
7964
|
const [types, setTypes] = useState16(["quest"]);
|
|
@@ -8066,12 +8070,26 @@ function InSceneQuestForm({
|
|
|
8066
8070
|
onClick: () => {
|
|
8067
8071
|
setStatus(s);
|
|
8068
8072
|
setIsStatusDropdownOpen(false);
|
|
8073
|
+
onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS[s]);
|
|
8069
8074
|
},
|
|
8070
8075
|
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
8071
8076
|
},
|
|
8072
8077
|
/* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS[s] } }),
|
|
8073
8078
|
s
|
|
8074
|
-
)))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ React15.createElement(
|
|
8079
|
+
)))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ React15.createElement(
|
|
8080
|
+
"input",
|
|
8081
|
+
{
|
|
8082
|
+
required: true,
|
|
8083
|
+
type: "text",
|
|
8084
|
+
placeholder: "Ex.: Refatorar M\xF3dulo X",
|
|
8085
|
+
value: name,
|
|
8086
|
+
onChange: (e) => {
|
|
8087
|
+
setName(e.target.value);
|
|
8088
|
+
onNameChange == null ? void 0 : onNameChange(e.target.value);
|
|
8089
|
+
},
|
|
8090
|
+
className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
|
|
8091
|
+
}
|
|
8092
|
+
)), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
|
|
8075
8093
|
"input",
|
|
8076
8094
|
{
|
|
8077
8095
|
type: "text",
|
|
@@ -8094,7 +8112,20 @@ function InSceneQuestForm({
|
|
|
8094
8112
|
onMentionClick,
|
|
8095
8113
|
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
8096
8114
|
}
|
|
8097
|
-
), /* @__PURE__ */ React15.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiEdit26, { size: 14 }))), !description && /* @__PURE__ */ React15.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ React15.createElement(
|
|
8115
|
+
), /* @__PURE__ */ React15.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiEdit26, { size: 14 }))), !description && /* @__PURE__ */ React15.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ React15.createElement(
|
|
8116
|
+
"button",
|
|
8117
|
+
{
|
|
8118
|
+
key: s,
|
|
8119
|
+
type: "button",
|
|
8120
|
+
onClick: () => {
|
|
8121
|
+
setSize(s);
|
|
8122
|
+
onSizeChange == null ? void 0 : onSizeChange(s);
|
|
8123
|
+
},
|
|
8124
|
+
className: "flex items-center gap-2 group cursor-pointer focus:outline-none"
|
|
8125
|
+
},
|
|
8126
|
+
/* @__PURE__ */ React15.createElement("div", { className: `w-4 h-4 rounded-[4px] border flex items-center justify-center transition-all duration-200 ${size === s ? "bg-indigo-500 border-indigo-500" : "border-slate-600 bg-transparent group-hover:border-slate-500"}` }, size === s && /* @__PURE__ */ React15.createElement(FiCheck9, { size: 12, className: "text-white" })),
|
|
8127
|
+
/* @__PURE__ */ React15.createElement("span", { className: `text-sm capitalize transition-colors ${size === s ? "text-white font-medium" : "text-slate-400 group-hover:text-slate-300"}` }, s)
|
|
8128
|
+
)))), /* @__PURE__ */ React15.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React15.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiPlus5, { size: 14 }), " Adicionar")), /* @__PURE__ */ React15.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React15.createElement(
|
|
8098
8129
|
CustomPropertyDisplay,
|
|
8099
8130
|
{
|
|
8100
8131
|
key: prop.id,
|
|
@@ -11603,6 +11634,26 @@ function XViewScene({
|
|
|
11603
11634
|
const handleStartVersioning = (nodeData) => {
|
|
11604
11635
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
11605
11636
|
};
|
|
11637
|
+
const handleCancelQuest = useCallback4(() => {
|
|
11638
|
+
const { graphGroup, ghostElements } = stateRef.current;
|
|
11639
|
+
if (ghostElements.node && graphGroup) {
|
|
11640
|
+
if (ghostElements.node.userData.labelObject) {
|
|
11641
|
+
graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
11642
|
+
if (ghostElements.node.userData.labelObject.material.map) ghostElements.node.userData.labelObject.material.map.dispose();
|
|
11643
|
+
ghostElements.node.userData.labelObject.material.dispose();
|
|
11644
|
+
}
|
|
11645
|
+
graphGroup.remove(ghostElements.node);
|
|
11646
|
+
ghostElements.node.traverse((child) => {
|
|
11647
|
+
if (child.material) {
|
|
11648
|
+
if (Array.isArray(child.material)) child.material.forEach((m) => m.dispose());
|
|
11649
|
+
else child.material.dispose();
|
|
11650
|
+
}
|
|
11651
|
+
if (child.geometry) child.geometry.dispose();
|
|
11652
|
+
});
|
|
11653
|
+
}
|
|
11654
|
+
stateRef.current.ghostElements = { node: null, line: null, aura: null };
|
|
11655
|
+
setQuestMode({ isActive: false });
|
|
11656
|
+
}, []);
|
|
11606
11657
|
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
11607
11658
|
const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
|
|
11608
11659
|
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
@@ -11619,9 +11670,7 @@ function XViewScene({
|
|
|
11619
11670
|
const sceneFileData = {
|
|
11620
11671
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11621
11672
|
nodes: sceneDataRef2.current.nodes,
|
|
11622
|
-
// <-- Mantém o cenário inicial inalterado
|
|
11623
11673
|
links: sceneDataRef2.current.links,
|
|
11624
|
-
// <-- Mantém o cenário inicial inalterado
|
|
11625
11674
|
quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
|
|
11626
11675
|
quest_links: graphDataRef.current[sceneConfigId2].links
|
|
11627
11676
|
};
|
|
@@ -11632,9 +11681,13 @@ function XViewScene({
|
|
|
11632
11681
|
ownerId: ownerId2,
|
|
11633
11682
|
datasetName: "Quests Internas (View)"
|
|
11634
11683
|
});
|
|
11635
|
-
const
|
|
11636
|
-
const
|
|
11637
|
-
|
|
11684
|
+
const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
|
|
11685
|
+
const { graphGroup, ghostElements } = stateRef2.current;
|
|
11686
|
+
if (ghostElements.node && graphGroup) {
|
|
11687
|
+
if (ghostElements.node.userData.labelObject) graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
11688
|
+
graphGroup.remove(ghostElements.node);
|
|
11689
|
+
}
|
|
11690
|
+
stateRef2.current.ghostElements = { node: null, line: null, aura: null };
|
|
11638
11691
|
addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
|
|
11639
11692
|
context.tweenToTarget(finalPosition, 1.2);
|
|
11640
11693
|
setters.setQuestMode({ isActive: false });
|
|
@@ -11672,12 +11725,9 @@ function XViewScene({
|
|
|
11672
11725
|
const viewFilePayload = {
|
|
11673
11726
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11674
11727
|
nodes: sceneDataRef2.current.nodes,
|
|
11675
|
-
// <-- Usa o estado original intocado
|
|
11676
11728
|
links: sceneDataRef2.current.links,
|
|
11677
|
-
// <-- Usa o estado original intocado
|
|
11678
11729
|
quest_nodes: specificParentData.nodes,
|
|
11679
11730
|
quest_links: specificParentData.links
|
|
11680
|
-
// Salva a conexão aqui!
|
|
11681
11731
|
};
|
|
11682
11732
|
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
11683
11733
|
} else {
|
|
@@ -13085,7 +13135,7 @@ function XViewScene({
|
|
|
13085
13135
|
}, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
|
|
13086
13136
|
useEffect21(() => {
|
|
13087
13137
|
function handleKeyDown(event) {
|
|
13088
|
-
var _a2, _b2, _c2
|
|
13138
|
+
var _a2, _b2, _c2;
|
|
13089
13139
|
const context = actionHandlerContext;
|
|
13090
13140
|
if (event.key === "Escape") {
|
|
13091
13141
|
if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
|
|
@@ -13096,7 +13146,9 @@ function XViewScene({
|
|
|
13096
13146
|
setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
13097
13147
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13098
13148
|
}
|
|
13099
|
-
if (
|
|
13149
|
+
if (questMode.isActive) {
|
|
13150
|
+
handleCancelQuest();
|
|
13151
|
+
}
|
|
13100
13152
|
if (stateRef.current.selectedNodes.size > 0) {
|
|
13101
13153
|
stateRef.current.selectedNodes.clear();
|
|
13102
13154
|
}
|
|
@@ -13105,16 +13157,42 @@ function XViewScene({
|
|
|
13105
13157
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
13106
13158
|
}
|
|
13107
13159
|
if (event.key.toLowerCase() === "q") {
|
|
13108
|
-
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((
|
|
13109
|
-
!detailsNode && // Condição nova
|
|
13110
|
-
!detailsLink && // Condição nova
|
|
13111
|
-
!ancestryLinkDetails && // Condição nova
|
|
13112
|
-
!imageViewer.visible && // Condição nova
|
|
13113
|
-
!editingAncestryRel.visible && // Condição nova
|
|
13114
|
-
!questMode.isActive;
|
|
13160
|
+
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
|
|
13115
13161
|
if (isUiClear) {
|
|
13116
|
-
const isView = ((
|
|
13162
|
+
const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
|
|
13117
13163
|
if (!isView) return;
|
|
13164
|
+
const { graphGroup, glowTexture, controls } = stateRef.current;
|
|
13165
|
+
if (graphGroup) {
|
|
13166
|
+
const basePosition = controls.target.clone();
|
|
13167
|
+
const offset = new THREE3.Vector3((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 5, 0);
|
|
13168
|
+
const ghostPosition = basePosition.add(offset);
|
|
13169
|
+
const ghostData = {
|
|
13170
|
+
id: "ghost_quest",
|
|
13171
|
+
name: "Nova Quest",
|
|
13172
|
+
color: "#64748b",
|
|
13173
|
+
// Cor padrão de "Backlog"
|
|
13174
|
+
size: "medium",
|
|
13175
|
+
intensity: 0,
|
|
13176
|
+
type: ["quest"]
|
|
13177
|
+
};
|
|
13178
|
+
const ghostNode = createNodeMesh(ghostData, ghostPosition, glowTexture);
|
|
13179
|
+
ghostNode.traverse((child) => {
|
|
13180
|
+
if (child.isMesh) {
|
|
13181
|
+
child.material.transparent = true;
|
|
13182
|
+
child.material.opacity = 0.75;
|
|
13183
|
+
}
|
|
13184
|
+
});
|
|
13185
|
+
graphGroup.add(ghostNode);
|
|
13186
|
+
if (ghostNode.userData.labelObject) {
|
|
13187
|
+
graphGroup.add(ghostNode.userData.labelObject);
|
|
13188
|
+
}
|
|
13189
|
+
stateRef.current.ghostElements = {
|
|
13190
|
+
node: ghostNode,
|
|
13191
|
+
line: null,
|
|
13192
|
+
// Quests não possuem linha de conexão na criação
|
|
13193
|
+
aura: ghostNode.getObjectByName("aura")
|
|
13194
|
+
};
|
|
13195
|
+
}
|
|
13118
13196
|
setQuestMode({ isActive: true });
|
|
13119
13197
|
}
|
|
13120
13198
|
}
|
|
@@ -13122,7 +13200,6 @@ function XViewScene({
|
|
|
13122
13200
|
window.addEventListener("keydown", handleKeyDown);
|
|
13123
13201
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
13124
13202
|
}, [
|
|
13125
|
-
// Dependências: sempre que um painel abrir ou fechar, o React atualiza o listener com os dados frescos
|
|
13126
13203
|
contextMenu.visible,
|
|
13127
13204
|
multiContextMenu.visible,
|
|
13128
13205
|
relationshipMenu.visible,
|
|
@@ -13137,7 +13214,9 @@ function XViewScene({
|
|
|
13137
13214
|
editingAncestryRel.visible,
|
|
13138
13215
|
questMode.isActive,
|
|
13139
13216
|
viewParams,
|
|
13140
|
-
actionHandlerContext
|
|
13217
|
+
actionHandlerContext,
|
|
13218
|
+
handleCancelQuest
|
|
13219
|
+
// <-- handleCancelQuest adicionado aqui
|
|
13141
13220
|
]);
|
|
13142
13221
|
if (isLoading || status === "loading" || permissionStatus === "loading") {
|
|
13143
13222
|
return /* @__PURE__ */ React24.createElement(LoadingScreen, null);
|
|
@@ -13233,7 +13312,10 @@ function XViewScene({
|
|
|
13233
13312
|
InSceneQuestForm,
|
|
13234
13313
|
{
|
|
13235
13314
|
onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
|
|
13236
|
-
onCancel:
|
|
13315
|
+
onCancel: handleCancelQuest,
|
|
13316
|
+
onNameChange: handleGhostNodeNameChange,
|
|
13317
|
+
onColorChange: handleGhostNodeColorChange,
|
|
13318
|
+
onSizeChange: handleGhostNodeSizeChange,
|
|
13237
13319
|
style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
13238
13320
|
refEl: formRef,
|
|
13239
13321
|
onOpenImageViewer: handleOpenImageViewer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lv-x-software-house/x_view",
|
|
3
|
-
"version": "1.2.4-dev.
|
|
3
|
+
"version": "1.2.4-dev.19",
|
|
4
4
|
"description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
|
|
5
5
|
"author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
|
|
6
6
|
"license": "UNLICENSED",
|