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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +111 -28
  2. package/dist/index.mjs +111 -28
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -116,6 +116,13 @@ function defineAbilityFor(role) {
116
116
  }
117
117
 
118
118
  // src/components/ContextMenu.jsx
119
+ var QUEST_STATUS_COLORS = {
120
+ "Backlog": "#64748b",
121
+ "In Progress": "#eab308",
122
+ "Review": "#a855f7",
123
+ "Done": "#22c55e"
124
+ };
125
+ var QUEST_STATUSES = ["Backlog", "In Progress", "Review", "Done"];
119
126
  function ContextMenu({
120
127
  data,
121
128
  userRole,
@@ -136,19 +143,21 @@ function ContextMenu({
136
143
  onFocusNode,
137
144
  onClose
138
145
  }) {
139
- var _a, _b;
146
+ var _a, _b, _c;
140
147
  const menuRef = (0, import_react.useRef)(null);
141
148
  const [menuPos, setMenuPos] = (0, import_react.useState)({ left: 0, top: 0 });
142
149
  const [menuView, setMenuView] = (0, import_react.useState)("main");
143
150
  const [selectedAncestry, setSelectedAncestry] = (0, import_react.useState)(null);
144
151
  const [versionSubMenu, setVersionSubMenu] = (0, import_react.useState)(null);
145
152
  const [isLinkCopied, setIsLinkCopied] = (0, import_react.useState)(false);
153
+ const [selectedQuestStatus, setSelectedQuestStatus] = (0, import_react.useState)(null);
146
154
  const ability = (0, import_react.useMemo)(() => defineAbilityFor(userRole), [userRole]);
147
155
  (0, import_react.useEffect)(() => {
148
156
  if (data.visible) {
149
157
  setMenuView("main");
150
158
  setSelectedAncestry(null);
151
159
  setVersionSubMenu(null);
160
+ setSelectedQuestStatus(null);
152
161
  }
153
162
  }, [data.visible, (_a = data.nodeData) == null ? void 0 : _a.id]);
154
163
  (0, import_react.useLayoutEffect)(() => {
@@ -163,7 +172,7 @@ function ContextMenu({
163
172
  if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
164
173
  if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
165
174
  setMenuPos({ left, top });
166
- }, [data, menuView, versionSubMenu]);
175
+ }, [data, menuView, versionSubMenu, selectedQuestStatus]);
167
176
  (0, import_react.useEffect)(() => {
168
177
  if (!data.visible) return;
169
178
  const handleClickOutside = (e) => {
@@ -206,7 +215,16 @@ function ContextMenu({
206
215
  var _a2;
207
216
  return c.targetNode && !(((_a2 = c.targetNode.version_node) == null ? void 0 : _a2.is_version) && String(c.targetNode.version_node.parent_node) === String(data.nodeData.id));
208
217
  });
209
- const groupedConnections = connections.reduce((acc, conn) => {
218
+ const isCurrentNodeQuest = ((_c = data.nodeData) == null ? void 0 : _c.is_quest) === true;
219
+ const commonConnections = isCurrentNodeQuest ? connections : connections.filter((c) => {
220
+ var _a2;
221
+ return !((_a2 = c.targetNode) == null ? void 0 : _a2.is_quest);
222
+ });
223
+ const questConnections = isCurrentNodeQuest ? [] : connections.filter((c) => {
224
+ var _a2;
225
+ return (_a2 = c.targetNode) == null ? void 0 : _a2.is_quest;
226
+ });
227
+ const groupedConnections = commonConnections.reduce((acc, conn) => {
210
228
  var _a2;
211
229
  const { targetNode } = conn;
212
230
  const groupingKey = ((_a2 = targetNode.version_node) == null ? void 0 : _a2.is_version) ? targetNode.version_node.parent_node : targetNode.id;
@@ -242,6 +260,20 @@ function ContextMenu({
242
260
  };
243
261
  }
244
262
  }).filter(Boolean);
263
+ const questsByStatus = {
264
+ "Backlog": [],
265
+ "In Progress": [],
266
+ "Review": [],
267
+ "Done": []
268
+ };
269
+ questConnections.forEach((conn) => {
270
+ const status = conn.targetNode.status || "Backlog";
271
+ if (questsByStatus[status]) {
272
+ questsByStatus[status].push(conn);
273
+ } else {
274
+ questsByStatus["Backlog"].push(conn);
275
+ }
276
+ });
245
277
  const availableAncestries = (ancestryData || []).filter(
246
278
  (ancestry) => String(ancestry.ancestral_node) === String(data.nodeData.id)
247
279
  );
@@ -299,7 +331,7 @@ function ContextMenu({
299
331
  const canCreateVersion = ability.can("create", "Versioning");
300
332
  const canReadVersion = ability.can("read", "Versioning");
301
333
  const shouldShowVersioningBtn = canCreateVersion || canReadVersion && hasVersions;
302
- return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conectar")), ability.can("create", "Node") && !((_a2 = data.nodeData) == null ? void 0 : _a2.is_quest) && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ import_react.default.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
334
+ return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conectar")), ability.can("create", "Node") && !((_a2 = data.nodeData) == null ? void 0 : _a2.is_quest) && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ import_react.default.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
303
335
  onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
304
336
  onClose();
305
337
  }, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Focar neste Node")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: (e) => handleCopyLink(e, data.nodeData), className: baseButtonClass, title: "Copiar Link para Compartilhar" }, isLinkCopied ? /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#4ade80", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ import_react.default.createElement("span", { className: isLinkCopied ? "text-green-400" : "" }, isLinkCopied ? "Copiado!" : "Copiar Link")), ability.can("dismiss", "Node") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("deleteConfirmation"), className: deleteButtonClass, title: "Excluir Node" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Excluir Node"))));
@@ -326,7 +358,7 @@ function ContextMenu({
326
358
  }
327
359
  const totalItems = availableAncestries.length + finalRenderableConnections.length;
328
360
  const isScrollable = totalItems > 10;
329
- return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), connections.length > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => handleExpandAndClose(connections.map((c) => c.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 ? "mb-4" : "mb-2"}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ import_react.default.createElement(
361
+ return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), commonConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => handleExpandAndClose(commonConnections.map((c) => c.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-4" : "mb-2"}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ import_react.default.createElement(
330
362
  "button",
331
363
  {
332
364
  key: anc.ancestry_id,
@@ -336,7 +368,17 @@ function ContextMenu({
336
368
  },
337
369
  /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M6 3v4a2 2 0 0 0 2 2h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 3v4a2 2 0 0 1-2 2h-4" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "3", r: "2" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "3", r: "2" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "11", r: "2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 13v6" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "21", r: "2" })),
338
370
  /* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, anc.name || `Ancestralidade #${anc.ancestry_id.substring(0, 8)}`)
339
- )), finalRenderableConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" })), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, finalRenderableConnections.map((group) => {
371
+ ))), questConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 ? "mb-4" : "mb-2"}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-sky-400/90" }, "Quests Relacionadas"), /* @__PURE__ */ import_react.default.createElement(
372
+ "button",
373
+ {
374
+ onClick: () => setMenuView("quest_statuses"),
375
+ className: baseButtonClass,
376
+ title: "Ver Quests Conectadas"
377
+ },
378
+ /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-sky-400" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "6" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "2" })),
379
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, "Status das Quests"),
380
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "text-xs px-2 py-0.5 bg-sky-500/20 text-sky-200 rounded-full" }, questConnections.length)
381
+ )), finalRenderableConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90 border-t border-white/5 pt-2" }, "Outros Nodes"), finalRenderableConnections.map((group) => {
340
382
  if (group.isVersionGroup) {
341
383
  return /* @__PURE__ */ import_react.default.createElement(
342
384
  "button",
@@ -366,6 +408,43 @@ function ContextMenu({
366
408
  }
367
409
  }))));
368
410
  };
411
+ const renderQuestStatusesView = () => {
412
+ return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Status das Quests"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, QUEST_STATUSES.map((status) => {
413
+ const count = questsByStatus[status].length;
414
+ const color = QUEST_STATUS_COLORS[status];
415
+ return /* @__PURE__ */ import_react.default.createElement(
416
+ "button",
417
+ {
418
+ key: status,
419
+ onClick: () => {
420
+ if (count > 0) {
421
+ setSelectedQuestStatus(status);
422
+ setMenuView("quest_list");
423
+ }
424
+ },
425
+ className: `${baseButtonClass} ${count === 0 ? "opacity-50 cursor-default hover:bg-transparent hover:text-slate-200" : ""}`
426
+ },
427
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: color } }),
428
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, status),
429
+ count > 0 && /* @__PURE__ */ import_react.default.createElement("span", { className: "text-xs px-2 py-0.5 bg-white/10 rounded-full" }, count)
430
+ );
431
+ })));
432
+ };
433
+ const renderQuestListView = () => {
434
+ const quests = questsByStatus[selectedQuestStatus] || [];
435
+ const isScrollable = quests.length > 10;
436
+ return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("quest_statuses"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: `Quests: ${selectedQuestStatus}` }, "Quests: ", selectedQuestStatus)), quests.length > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => handleExpandAndClose(quests.map((q) => q.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, quests.map((conn) => /* @__PURE__ */ import_react.default.createElement(
437
+ "button",
438
+ {
439
+ key: conn.targetNode.id,
440
+ onClick: () => handleConnectionClick({ links: [conn.link] }),
441
+ className: baseButtonClass,
442
+ title: `Expandir Quest ${conn.targetNode.name}`
443
+ },
444
+ /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "opacity-70" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "13 17 18 12 13 7" }), /* @__PURE__ */ import_react.default.createElement("polyline", { points: "6 17 11 12 6 7" })),
445
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
446
+ ))));
447
+ };
369
448
  const renderAncestryActionsView = () => {
370
449
  const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
371
450
  return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
@@ -427,7 +506,7 @@ function ContextMenu({
427
506
  onDoubleClick: swallow
428
507
  },
429
508
  /* @__PURE__ */ import_react.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
430
- /* @__PURE__ */ import_react.default.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
509
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "quest_statuses" && renderQuestStatusesView(), menuView === "quest_list" && renderQuestListView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
431
510
  );
432
511
  }
433
512
 
@@ -1011,7 +1090,8 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
1011
1090
  const size = nodeData.size || "medium";
1012
1091
  const scale = NODE_SCALE_FACTORS[size] || 1;
1013
1092
  mesh.scale.set(scale, scale, scale);
1014
- const label = createTextSprite(nodeData.name);
1093
+ const labelText = nodeData.is_quest && nodeData.raw_title ? nodeData.raw_title : nodeData.name;
1094
+ const label = createTextSprite(labelText);
1015
1095
  label.name = "label";
1016
1096
  mesh.userData.labelObject = label;
1017
1097
  mesh.userData.labelOffset = new THREE.Vector3(0, 3.8, 0);
@@ -1116,13 +1196,15 @@ var updateExistingNodeVisuals = (state, updatedNode) => {
1116
1196
  const size = updatedNode.size || "medium";
1117
1197
  const scale = NODE_SCALE_FACTORS[size] || 1;
1118
1198
  existingMesh.scale.set(scale, scale, scale);
1119
- if (existingMesh.userData.name !== updatedNode.name) {
1199
+ const oldText = existingMesh.userData.is_quest && existingMesh.userData.raw_title ? existingMesh.userData.raw_title : existingMesh.userData.name;
1200
+ const newText = updatedNode.is_quest && updatedNode.raw_title ? updatedNode.raw_title : updatedNode.name;
1201
+ if (oldText !== newText) {
1120
1202
  const oldLabelToDispose = existingMesh.userData.labelObject;
1121
1203
  if (oldLabelToDispose && state.graphGroup) {
1122
1204
  state.graphGroup.remove(oldLabelToDispose);
1123
1205
  if (oldLabelToDispose.material) oldLabelToDispose.material.dispose();
1124
1206
  }
1125
- const newLabel = createTextSprite(updatedNode.name || "");
1207
+ const newLabel = createTextSprite(newText || "");
1126
1208
  newLabel.name = "label";
1127
1209
  existingMesh.userData.labelObject = newLabel;
1128
1210
  if (state.graphGroup) {
@@ -7967,7 +8049,7 @@ function InSceneVersionForm({
7967
8049
  // src/components/InSceneQuestForm.jsx
7968
8050
  var import_react16 = __toESM(require("react"));
7969
8051
  var import_fi14 = require("react-icons/fi");
7970
- var QUEST_STATUS_COLORS = {
8052
+ var QUEST_STATUS_COLORS2 = {
7971
8053
  "Backlog": "#64748b",
7972
8054
  "In Progress": "#eab308",
7973
8055
  "Review": "#a855f7",
@@ -8052,7 +8134,7 @@ function InSceneQuestForm({
8052
8134
  raw_title: name.trim(),
8053
8135
  // Salva o título puro como fallback ou metadado útil
8054
8136
  type: types,
8055
- color: QUEST_STATUS_COLORS[status],
8137
+ color: QUEST_STATUS_COLORS2[status],
8056
8138
  status,
8057
8139
  size,
8058
8140
  intensity,
@@ -8078,7 +8160,7 @@ function InSceneQuestForm({
8078
8160
  onContextMenu: swallow,
8079
8161
  onDoubleClick: swallow
8080
8162
  },
8081
- /* @__PURE__ */ import_react16.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS[status]}, transparent)` } }),
8163
+ /* @__PURE__ */ import_react16.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS2[status]}, transparent)` } }),
8082
8164
  /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react16.default.createElement("div", null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova quest")), /* @__PURE__ */ import_react16.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")), /* @__PURE__ */ import_react16.default.createElement(
8083
8165
  "button",
8084
8166
  {
@@ -8099,7 +8181,7 @@ function InSceneQuestForm({
8099
8181
  onChange: (e) => {
8100
8182
  const val = e.target.value;
8101
8183
  setName(val);
8102
- onNameChange == null ? void 0 : onNameChange(`${viewName} - ${questCounter} - \xBB ${val || "Nova Quest"}`);
8184
+ onNameChange == null ? void 0 : onNameChange(val || "Nova Quest");
8103
8185
  },
8104
8186
  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"
8105
8187
  }
@@ -8110,20 +8192,20 @@ function InSceneQuestForm({
8110
8192
  onClick: () => setIsStatusDropdownOpen(!isStatusDropdownOpen),
8111
8193
  className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
8112
8194
  },
8113
- /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS[status] } }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-slate-200 font-medium" }, status)),
8195
+ /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS2[status] } }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-slate-200 font-medium" }, status)),
8114
8196
  /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
8115
- ), isStatusDropdownOpen && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ import_react16.default.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS).map((s) => /* @__PURE__ */ import_react16.default.createElement(
8197
+ ), isStatusDropdownOpen && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ import_react16.default.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS2).map((s) => /* @__PURE__ */ import_react16.default.createElement(
8116
8198
  "li",
8117
8199
  {
8118
8200
  key: s,
8119
8201
  onClick: () => {
8120
8202
  setStatus(s);
8121
8203
  setIsStatusDropdownOpen(false);
8122
- onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS[s]);
8204
+ onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS2[s]);
8123
8205
  },
8124
8206
  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"}`
8125
8207
  },
8126
- /* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS[s] } }),
8208
+ /* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
8127
8209
  s
8128
8210
  )))))), /* @__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(
8129
8211
  "input",
@@ -8679,7 +8761,7 @@ function NodeDetailsPanel({
8679
8761
  // src/components/QuestDetailsPanel.jsx
8680
8762
  var import_react18 = __toESM(require("react"));
8681
8763
  var import_fi16 = require("react-icons/fi");
8682
- var QUEST_STATUS_COLORS2 = {
8764
+ var QUEST_STATUS_COLORS3 = {
8683
8765
  "Backlog": "#64748b",
8684
8766
  "In Progress": "#eab308",
8685
8767
  "Review": "#a855f7",
@@ -8793,7 +8875,7 @@ function QuestDetailsPanel({
8793
8875
  };
8794
8876
  const handleStatusChange = (newStatus) => {
8795
8877
  setStatus(newStatus);
8796
- const newColor = QUEST_STATUS_COLORS2[newStatus];
8878
+ const newColor = QUEST_STATUS_COLORS3[newStatus];
8797
8879
  onColorChange == null ? void 0 : onColorChange(node.id, newColor);
8798
8880
  onDataUpdate == null ? void 0 : onDataUpdate({ ...node, status: newStatus, color: newColor });
8799
8881
  };
@@ -8866,7 +8948,7 @@ function QuestDetailsPanel({
8866
8948
  raw_title: currentRawTitle.trim(),
8867
8949
  // Salva o título simples
8868
8950
  type: currentTypes,
8869
- color: QUEST_STATUS_COLORS2[currentStatus],
8951
+ color: QUEST_STATUS_COLORS3[currentStatus],
8870
8952
  status: currentStatus,
8871
8953
  size,
8872
8954
  description: currentDescription,
@@ -8937,7 +9019,7 @@ function QuestDetailsPanel({
8937
9019
  onImageClick: handleImageClickFromText,
8938
9020
  onSaveDescription: handleSaveDescriptionInline
8939
9021
  }
8940
- ) : /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS2[status]}, transparent)` } }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react18.default.createElement("div", null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ import_react18.default.createElement("button", { onClick: handleCopyLink, className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-sky-400"}`, title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Quest" }, isLinkCopied ? /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiLink, { size: 12 }))), /* @__PURE__ */ import_react18.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react18.default.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Cancelar" }, "\xD7")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ import_react18.default.createElement(
9022
+ ) : /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS3[status]}, transparent)` } }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react18.default.createElement("div", null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ import_react18.default.createElement("button", { onClick: handleCopyLink, className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-sky-400"}`, title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Quest" }, isLinkCopied ? /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiLink, { size: 12 }))), /* @__PURE__ */ import_react18.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react18.default.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Cancelar" }, "\xD7")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ import_react18.default.createElement(
8941
9023
  "input",
8942
9024
  {
8943
9025
  type: "text",
@@ -8954,9 +9036,9 @@ function QuestDetailsPanel({
8954
9036
  disabled: !canEdit,
8955
9037
  className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 transition-colors flex items-center justify-between ${canEdit ? "hover:border-white/20 focus:ring-2 focus:ring-indigo-400/60 cursor-pointer" : "cursor-default opacity-80"}`
8956
9038
  },
8957
- /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS2[status] } }), /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-slate-200 font-medium" }, status)),
9039
+ /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS3[status] } }), /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-slate-200 font-medium" }, status)),
8958
9040
  canEdit && /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
8959
- ), isStatusDropdownOpen && canEdit && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ import_react18.default.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS2).map((s) => /* @__PURE__ */ import_react18.default.createElement(
9041
+ ), isStatusDropdownOpen && canEdit && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ import_react18.default.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS3).map((s) => /* @__PURE__ */ import_react18.default.createElement(
8960
9042
  "li",
8961
9043
  {
8962
9044
  key: s,
@@ -8966,7 +9048,7 @@ function QuestDetailsPanel({
8966
9048
  },
8967
9049
  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"}`
8968
9050
  },
8969
- /* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
9051
+ /* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
8970
9052
  s
8971
9053
  )))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ import_react18.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, canEdit && t !== "quest" && /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiX, { size: 12 })))), canEdit && /* @__PURE__ */ import_react18.default.createElement(
8972
9054
  "input",
@@ -11852,7 +11934,9 @@ function XViewScene({
11852
11934
  if (oldLabel.material.map) oldLabel.material.map.dispose();
11853
11935
  oldLabel.material.dispose();
11854
11936
  }
11855
- const newLabel = createTextSprite(newName || "");
11937
+ const isQuest = mesh.userData.is_quest;
11938
+ const displayText = isQuest && newRawTitle !== void 0 ? newRawTitle : newName;
11939
+ const newLabel = createTextSprite(displayText || "");
11856
11940
  graphGroup.add(newLabel);
11857
11941
  mesh.userData.labelObject = newLabel;
11858
11942
  mesh.userData.name = newName;
@@ -12033,15 +12117,14 @@ function XViewScene({
12033
12117
  graphDataRef.current[sceneConfigId2] = { nodes: [], links: [] };
12034
12118
  }
12035
12119
  graphDataRef.current[sceneConfigId2].nodes.push(newNode);
12036
- sceneDataRef2.current.nodes.push(newNode);
12037
12120
  const sceneFileData = {
12038
12121
  parent_dbs: sceneDataRef2.current.parent_dbs,
12039
12122
  nodes: sceneDataRef2.current.nodes,
12123
+ // Permanece intacto, como estava no último save de cena inicial
12040
12124
  links: sceneDataRef2.current.links,
12041
12125
  quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
12042
12126
  quest_links: graphDataRef.current[sceneConfigId2].links,
12043
12127
  quest_counter: currentCounter + 1
12044
- // NOVO: Incrementa o contador nos metadados
12045
12128
  };
12046
12129
  try {
12047
12130
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
package/dist/index.mjs CHANGED
@@ -72,6 +72,13 @@ function defineAbilityFor(role) {
72
72
  }
73
73
 
74
74
  // src/components/ContextMenu.jsx
75
+ var QUEST_STATUS_COLORS = {
76
+ "Backlog": "#64748b",
77
+ "In Progress": "#eab308",
78
+ "Review": "#a855f7",
79
+ "Done": "#22c55e"
80
+ };
81
+ var QUEST_STATUSES = ["Backlog", "In Progress", "Review", "Done"];
75
82
  function ContextMenu({
76
83
  data,
77
84
  userRole,
@@ -92,19 +99,21 @@ function ContextMenu({
92
99
  onFocusNode,
93
100
  onClose
94
101
  }) {
95
- var _a, _b;
102
+ var _a, _b, _c;
96
103
  const menuRef = useRef(null);
97
104
  const [menuPos, setMenuPos] = useState({ left: 0, top: 0 });
98
105
  const [menuView, setMenuView] = useState("main");
99
106
  const [selectedAncestry, setSelectedAncestry] = useState(null);
100
107
  const [versionSubMenu, setVersionSubMenu] = useState(null);
101
108
  const [isLinkCopied, setIsLinkCopied] = useState(false);
109
+ const [selectedQuestStatus, setSelectedQuestStatus] = useState(null);
102
110
  const ability = useMemo(() => defineAbilityFor(userRole), [userRole]);
103
111
  useEffect(() => {
104
112
  if (data.visible) {
105
113
  setMenuView("main");
106
114
  setSelectedAncestry(null);
107
115
  setVersionSubMenu(null);
116
+ setSelectedQuestStatus(null);
108
117
  }
109
118
  }, [data.visible, (_a = data.nodeData) == null ? void 0 : _a.id]);
110
119
  useLayoutEffect(() => {
@@ -119,7 +128,7 @@ function ContextMenu({
119
128
  if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
120
129
  if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
121
130
  setMenuPos({ left, top });
122
- }, [data, menuView, versionSubMenu]);
131
+ }, [data, menuView, versionSubMenu, selectedQuestStatus]);
123
132
  useEffect(() => {
124
133
  if (!data.visible) return;
125
134
  const handleClickOutside = (e) => {
@@ -162,7 +171,16 @@ function ContextMenu({
162
171
  var _a2;
163
172
  return c.targetNode && !(((_a2 = c.targetNode.version_node) == null ? void 0 : _a2.is_version) && String(c.targetNode.version_node.parent_node) === String(data.nodeData.id));
164
173
  });
165
- const groupedConnections = connections.reduce((acc, conn) => {
174
+ const isCurrentNodeQuest = ((_c = data.nodeData) == null ? void 0 : _c.is_quest) === true;
175
+ const commonConnections = isCurrentNodeQuest ? connections : connections.filter((c) => {
176
+ var _a2;
177
+ return !((_a2 = c.targetNode) == null ? void 0 : _a2.is_quest);
178
+ });
179
+ const questConnections = isCurrentNodeQuest ? [] : connections.filter((c) => {
180
+ var _a2;
181
+ return (_a2 = c.targetNode) == null ? void 0 : _a2.is_quest;
182
+ });
183
+ const groupedConnections = commonConnections.reduce((acc, conn) => {
166
184
  var _a2;
167
185
  const { targetNode } = conn;
168
186
  const groupingKey = ((_a2 = targetNode.version_node) == null ? void 0 : _a2.is_version) ? targetNode.version_node.parent_node : targetNode.id;
@@ -198,6 +216,20 @@ function ContextMenu({
198
216
  };
199
217
  }
200
218
  }).filter(Boolean);
219
+ const questsByStatus = {
220
+ "Backlog": [],
221
+ "In Progress": [],
222
+ "Review": [],
223
+ "Done": []
224
+ };
225
+ questConnections.forEach((conn) => {
226
+ const status = conn.targetNode.status || "Backlog";
227
+ if (questsByStatus[status]) {
228
+ questsByStatus[status].push(conn);
229
+ } else {
230
+ questsByStatus["Backlog"].push(conn);
231
+ }
232
+ });
201
233
  const availableAncestries = (ancestryData || []).filter(
202
234
  (ancestry) => String(ancestry.ancestral_node) === String(data.nodeData.id)
203
235
  );
@@ -255,7 +287,7 @@ function ContextMenu({
255
287
  const canCreateVersion = ability.can("create", "Versioning");
256
288
  const canReadVersion = ability.can("read", "Versioning");
257
289
  const shouldShowVersioningBtn = canCreateVersion || canReadVersion && hasVersions;
258
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ React.createElement("span", null, "Conectar")), ability.can("create", "Node") && !((_a2 = data.nodeData) == null ? void 0 : _a2.is_quest) && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ React.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ React.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ React.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ React.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ React.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ React.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ React.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => {
290
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ React.createElement("span", null, "Conectar")), ability.can("create", "Node") && !((_a2 = data.nodeData) == null ? void 0 : _a2.is_quest) && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ React.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ React.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ React.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ React.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ React.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ React.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ React.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => {
259
291
  onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
260
292
  onClose();
261
293
  }, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ React.createElement("span", null, "Focar neste Node")), /* @__PURE__ */ React.createElement("button", { onClick: (e) => handleCopyLink(e, data.nodeData), className: baseButtonClass, title: "Copiar Link para Compartilhar" }, isLinkCopied ? /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#4ade80", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ React.createElement("span", { className: isLinkCopied ? "text-green-400" : "" }, isLinkCopied ? "Copiado!" : "Copiar Link")), ability.can("dismiss", "Node") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ React.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ React.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss")), /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("deleteConfirmation"), className: deleteButtonClass, title: "Excluir Node" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React.createElement("span", null, "Excluir Node"))));
@@ -282,7 +314,7 @@ function ContextMenu({
282
314
  }
283
315
  const totalItems = availableAncestries.length + finalRenderableConnections.length;
284
316
  const isScrollable = totalItems > 10;
285
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), connections.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(connections.map((c) => c.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 ? "mb-4" : "mb-2"}` }, /* @__PURE__ */ React.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ React.createElement(
317
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), commonConnections.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(commonConnections.map((c) => c.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-4" : "mb-2"}` }, /* @__PURE__ */ React.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ React.createElement(
286
318
  "button",
287
319
  {
288
320
  key: anc.ancestry_id,
@@ -292,7 +324,17 @@ function ContextMenu({
292
324
  },
293
325
  /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M6 3v4a2 2 0 0 0 2 2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M18 3v4a2 2 0 0 1-2 2h-4" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "3", r: "2" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "3", r: "2" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "11", r: "2" }), /* @__PURE__ */ React.createElement("path", { d: "M12 13v6" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "21", r: "2" })),
294
326
  /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, anc.name || `Ancestralidade #${anc.ancestry_id.substring(0, 8)}`)
295
- )), finalRenderableConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" })), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, finalRenderableConnections.map((group) => {
327
+ ))), questConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 ? "mb-4" : "mb-2"}` }, /* @__PURE__ */ React.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-sky-400/90" }, "Quests Relacionadas"), /* @__PURE__ */ React.createElement(
328
+ "button",
329
+ {
330
+ onClick: () => setMenuView("quest_statuses"),
331
+ className: baseButtonClass,
332
+ title: "Ver Quests Conectadas"
333
+ },
334
+ /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-sky-400" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "6" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "2" })),
335
+ /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, "Status das Quests"),
336
+ /* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-sky-500/20 text-sky-200 rounded-full" }, questConnections.length)
337
+ )), finalRenderableConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90 border-t border-white/5 pt-2" }, "Outros Nodes"), finalRenderableConnections.map((group) => {
296
338
  if (group.isVersionGroup) {
297
339
  return /* @__PURE__ */ React.createElement(
298
340
  "button",
@@ -322,6 +364,43 @@ function ContextMenu({
322
364
  }
323
365
  }))));
324
366
  };
367
+ const renderQuestStatusesView = () => {
368
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Status das Quests"))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, QUEST_STATUSES.map((status) => {
369
+ const count = questsByStatus[status].length;
370
+ const color = QUEST_STATUS_COLORS[status];
371
+ return /* @__PURE__ */ React.createElement(
372
+ "button",
373
+ {
374
+ key: status,
375
+ onClick: () => {
376
+ if (count > 0) {
377
+ setSelectedQuestStatus(status);
378
+ setMenuView("quest_list");
379
+ }
380
+ },
381
+ className: `${baseButtonClass} ${count === 0 ? "opacity-50 cursor-default hover:bg-transparent hover:text-slate-200" : ""}`
382
+ },
383
+ /* @__PURE__ */ React.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: color } }),
384
+ /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, status),
385
+ count > 0 && /* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-white/10 rounded-full" }, count)
386
+ );
387
+ })));
388
+ };
389
+ const renderQuestListView = () => {
390
+ const quests = questsByStatus[selectedQuestStatus] || [];
391
+ const isScrollable = quests.length > 10;
392
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("quest_statuses"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: `Quests: ${selectedQuestStatus}` }, "Quests: ", selectedQuestStatus)), quests.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(quests.map((q) => q.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, quests.map((conn) => /* @__PURE__ */ React.createElement(
393
+ "button",
394
+ {
395
+ key: conn.targetNode.id,
396
+ onClick: () => handleConnectionClick({ links: [conn.link] }),
397
+ className: baseButtonClass,
398
+ title: `Expandir Quest ${conn.targetNode.name}`
399
+ },
400
+ /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "opacity-70" }, /* @__PURE__ */ React.createElement("polyline", { points: "13 17 18 12 13 7" }), /* @__PURE__ */ React.createElement("polyline", { points: "6 17 11 12 6 7" })),
401
+ /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
402
+ ))));
403
+ };
325
404
  const renderAncestryActionsView = () => {
326
405
  const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
327
406
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => {
@@ -383,7 +462,7 @@ function ContextMenu({
383
462
  onDoubleClick: swallow
384
463
  },
385
464
  /* @__PURE__ */ React.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
386
- /* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
465
+ /* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "quest_statuses" && renderQuestStatusesView(), menuView === "quest_list" && renderQuestListView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
387
466
  );
388
467
  }
389
468
 
@@ -967,7 +1046,8 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
967
1046
  const size = nodeData.size || "medium";
968
1047
  const scale = NODE_SCALE_FACTORS[size] || 1;
969
1048
  mesh.scale.set(scale, scale, scale);
970
- const label = createTextSprite(nodeData.name);
1049
+ const labelText = nodeData.is_quest && nodeData.raw_title ? nodeData.raw_title : nodeData.name;
1050
+ const label = createTextSprite(labelText);
971
1051
  label.name = "label";
972
1052
  mesh.userData.labelObject = label;
973
1053
  mesh.userData.labelOffset = new THREE.Vector3(0, 3.8, 0);
@@ -1072,13 +1152,15 @@ var updateExistingNodeVisuals = (state, updatedNode) => {
1072
1152
  const size = updatedNode.size || "medium";
1073
1153
  const scale = NODE_SCALE_FACTORS[size] || 1;
1074
1154
  existingMesh.scale.set(scale, scale, scale);
1075
- if (existingMesh.userData.name !== updatedNode.name) {
1155
+ const oldText = existingMesh.userData.is_quest && existingMesh.userData.raw_title ? existingMesh.userData.raw_title : existingMesh.userData.name;
1156
+ const newText = updatedNode.is_quest && updatedNode.raw_title ? updatedNode.raw_title : updatedNode.name;
1157
+ if (oldText !== newText) {
1076
1158
  const oldLabelToDispose = existingMesh.userData.labelObject;
1077
1159
  if (oldLabelToDispose && state.graphGroup) {
1078
1160
  state.graphGroup.remove(oldLabelToDispose);
1079
1161
  if (oldLabelToDispose.material) oldLabelToDispose.material.dispose();
1080
1162
  }
1081
- const newLabel = createTextSprite(updatedNode.name || "");
1163
+ const newLabel = createTextSprite(newText || "");
1082
1164
  newLabel.name = "label";
1083
1165
  existingMesh.userData.labelObject = newLabel;
1084
1166
  if (state.graphGroup) {
@@ -7954,7 +8036,7 @@ function InSceneVersionForm({
7954
8036
  // src/components/InSceneQuestForm.jsx
7955
8037
  import React15, { useState as useState16, useRef as useRef12 } from "react";
7956
8038
  import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4, FiChevronDown as FiChevronDown5 } from "react-icons/fi";
7957
- var QUEST_STATUS_COLORS = {
8039
+ var QUEST_STATUS_COLORS2 = {
7958
8040
  "Backlog": "#64748b",
7959
8041
  "In Progress": "#eab308",
7960
8042
  "Review": "#a855f7",
@@ -8039,7 +8121,7 @@ function InSceneQuestForm({
8039
8121
  raw_title: name.trim(),
8040
8122
  // Salva o título puro como fallback ou metadado útil
8041
8123
  type: types,
8042
- color: QUEST_STATUS_COLORS[status],
8124
+ color: QUEST_STATUS_COLORS2[status],
8043
8125
  status,
8044
8126
  size,
8045
8127
  intensity,
@@ -8065,7 +8147,7 @@ function InSceneQuestForm({
8065
8147
  onContextMenu: swallow,
8066
8148
  onDoubleClick: swallow
8067
8149
  },
8068
- /* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS[status]}, transparent)` } }),
8150
+ /* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS2[status]}, transparent)` } }),
8069
8151
  /* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement(FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova quest")), /* @__PURE__ */ React15.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")), /* @__PURE__ */ React15.createElement(
8070
8152
  "button",
8071
8153
  {
@@ -8086,7 +8168,7 @@ function InSceneQuestForm({
8086
8168
  onChange: (e) => {
8087
8169
  const val = e.target.value;
8088
8170
  setName(val);
8089
- onNameChange == null ? void 0 : onNameChange(`${viewName} - ${questCounter} - \xBB ${val || "Nova Quest"}`);
8171
+ onNameChange == null ? void 0 : onNameChange(val || "Nova Quest");
8090
8172
  },
8091
8173
  className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
8092
8174
  }
@@ -8097,20 +8179,20 @@ function InSceneQuestForm({
8097
8179
  onClick: () => setIsStatusDropdownOpen(!isStatusDropdownOpen),
8098
8180
  className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
8099
8181
  },
8100
- /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS[status] } }), /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, status)),
8182
+ /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS2[status] } }), /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, status)),
8101
8183
  /* @__PURE__ */ React15.createElement(FiChevronDown5, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
8102
- ), isStatusDropdownOpen && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React15.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS).map((s) => /* @__PURE__ */ React15.createElement(
8184
+ ), isStatusDropdownOpen && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React15.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS2).map((s) => /* @__PURE__ */ React15.createElement(
8103
8185
  "li",
8104
8186
  {
8105
8187
  key: s,
8106
8188
  onClick: () => {
8107
8189
  setStatus(s);
8108
8190
  setIsStatusDropdownOpen(false);
8109
- onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS[s]);
8191
+ onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS2[s]);
8110
8192
  },
8111
8193
  className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
8112
8194
  },
8113
- /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS[s] } }),
8195
+ /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
8114
8196
  s
8115
8197
  )))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
8116
8198
  "input",
@@ -8666,7 +8748,7 @@ function NodeDetailsPanel({
8666
8748
  // src/components/QuestDetailsPanel.jsx
8667
8749
  import React17, { useState as useState18, useEffect as useEffect16, useRef as useRef14 } from "react";
8668
8750
  import { FiPlus as FiPlus7, FiX as FiX6, FiCheck as FiCheck11, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4, FiLink as FiLink6, FiTarget as FiTarget2, FiChevronDown as FiChevronDown6 } from "react-icons/fi";
8669
- var QUEST_STATUS_COLORS2 = {
8751
+ var QUEST_STATUS_COLORS3 = {
8670
8752
  "Backlog": "#64748b",
8671
8753
  "In Progress": "#eab308",
8672
8754
  "Review": "#a855f7",
@@ -8780,7 +8862,7 @@ function QuestDetailsPanel({
8780
8862
  };
8781
8863
  const handleStatusChange = (newStatus) => {
8782
8864
  setStatus(newStatus);
8783
- const newColor = QUEST_STATUS_COLORS2[newStatus];
8865
+ const newColor = QUEST_STATUS_COLORS3[newStatus];
8784
8866
  onColorChange == null ? void 0 : onColorChange(node.id, newColor);
8785
8867
  onDataUpdate == null ? void 0 : onDataUpdate({ ...node, status: newStatus, color: newColor });
8786
8868
  };
@@ -8853,7 +8935,7 @@ function QuestDetailsPanel({
8853
8935
  raw_title: currentRawTitle.trim(),
8854
8936
  // Salva o título simples
8855
8937
  type: currentTypes,
8856
- color: QUEST_STATUS_COLORS2[currentStatus],
8938
+ color: QUEST_STATUS_COLORS3[currentStatus],
8857
8939
  status: currentStatus,
8858
8940
  size,
8859
8941
  description: currentDescription,
@@ -8924,7 +9006,7 @@ function QuestDetailsPanel({
8924
9006
  onImageClick: handleImageClickFromText,
8925
9007
  onSaveDescription: handleSaveDescriptionInline
8926
9008
  }
8927
- ) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS2[status]}, transparent)` } }), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React17.createElement(FiTarget2, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ React17.createElement("button", { onClick: handleCopyLink, className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-sky-400"}`, title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Quest" }, isLinkCopied ? /* @__PURE__ */ React17.createElement(FiCheck11, { size: 12 }) : /* @__PURE__ */ React17.createElement(FiLink6, { size: 12 }))), /* @__PURE__ */ React17.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ React17.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Cancelar" }, "\xD7")), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ React17.createElement(
9009
+ ) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS3[status]}, transparent)` } }), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React17.createElement(FiTarget2, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ React17.createElement("button", { onClick: handleCopyLink, className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-sky-400"}`, title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Quest" }, isLinkCopied ? /* @__PURE__ */ React17.createElement(FiCheck11, { size: 12 }) : /* @__PURE__ */ React17.createElement(FiLink6, { size: 12 }))), /* @__PURE__ */ React17.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ React17.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Cancelar" }, "\xD7")), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ React17.createElement(
8928
9010
  "input",
8929
9011
  {
8930
9012
  type: "text",
@@ -8941,9 +9023,9 @@ function QuestDetailsPanel({
8941
9023
  disabled: !canEdit,
8942
9024
  className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 transition-colors flex items-center justify-between ${canEdit ? "hover:border-white/20 focus:ring-2 focus:ring-indigo-400/60 cursor-pointer" : "cursor-default opacity-80"}`
8943
9025
  },
8944
- /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS2[status] } }), /* @__PURE__ */ React17.createElement("span", { className: "text-slate-200 font-medium" }, status)),
9026
+ /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS3[status] } }), /* @__PURE__ */ React17.createElement("span", { className: "text-slate-200 font-medium" }, status)),
8945
9027
  canEdit && /* @__PURE__ */ React17.createElement(FiChevronDown6, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
8946
- ), isStatusDropdownOpen && canEdit && /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React17.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS2).map((s) => /* @__PURE__ */ React17.createElement(
9028
+ ), isStatusDropdownOpen && canEdit && /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React17.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS3).map((s) => /* @__PURE__ */ React17.createElement(
8947
9029
  "li",
8948
9030
  {
8949
9031
  key: s,
@@ -8953,7 +9035,7 @@ function QuestDetailsPanel({
8953
9035
  },
8954
9036
  className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
8955
9037
  },
8956
- /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
9038
+ /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
8957
9039
  s
8958
9040
  )))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ React17.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React17.createElement(FiX6, { size: 12 })))), canEdit && /* @__PURE__ */ React17.createElement(
8959
9041
  "input",
@@ -11852,7 +11934,9 @@ function XViewScene({
11852
11934
  if (oldLabel.material.map) oldLabel.material.map.dispose();
11853
11935
  oldLabel.material.dispose();
11854
11936
  }
11855
- const newLabel = createTextSprite(newName || "");
11937
+ const isQuest = mesh.userData.is_quest;
11938
+ const displayText = isQuest && newRawTitle !== void 0 ? newRawTitle : newName;
11939
+ const newLabel = createTextSprite(displayText || "");
11856
11940
  graphGroup.add(newLabel);
11857
11941
  mesh.userData.labelObject = newLabel;
11858
11942
  mesh.userData.name = newName;
@@ -12033,15 +12117,14 @@ function XViewScene({
12033
12117
  graphDataRef.current[sceneConfigId2] = { nodes: [], links: [] };
12034
12118
  }
12035
12119
  graphDataRef.current[sceneConfigId2].nodes.push(newNode);
12036
- sceneDataRef2.current.nodes.push(newNode);
12037
12120
  const sceneFileData = {
12038
12121
  parent_dbs: sceneDataRef2.current.parent_dbs,
12039
12122
  nodes: sceneDataRef2.current.nodes,
12123
+ // Permanece intacto, como estava no último save de cena inicial
12040
12124
  links: sceneDataRef2.current.links,
12041
12125
  quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
12042
12126
  quest_links: graphDataRef.current[sceneConfigId2].links,
12043
12127
  quest_counter: currentCounter + 1
12044
- // NOVO: Incrementa o contador nos metadados
12045
12128
  };
12046
12129
  try {
12047
12130
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
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.27",
3
+ "version": "1.2.4-dev.29",
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",