@lv-x-software-house/x_view 1.2.5 → 1.2.6-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +178 -71
  2. package/dist/index.mjs +182 -72
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2357,6 +2357,8 @@ var userActionHandlers = {
2357
2357
  milestones: sceneDataRef.current.milestones || [],
2358
2358
  quest_counter: sceneDataRef.current.quest_counter || 1
2359
2359
  };
2360
+ sceneDataRef.current.quest_nodes = specificParentData.nodes;
2361
+ sceneDataRef.current.quest_links = specificParentData.links;
2360
2362
  await context.actions.save_view_data(
2361
2363
  context.sceneSaveUrl,
2362
2364
  viewFilePayload
@@ -13007,27 +13009,45 @@ var GroupItem = ({
13007
13009
  }
13008
13010
  ),
13009
13011
  group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
13010
- const isValid = availableIds.has(String(anc.ancestry_id));
13012
+ const isValid = anc.type === "ancestry" || !anc.type ? availableIds.has(String(anc.ancestry_id || anc.id)) : true;
13013
+ const isAncestry = anc.type === "ancestry" || !anc.type;
13014
+ const itemId = isAncestry ? anc.ancestry_id : anc.id;
13015
+ let Icon = import_fi22.FiLayers;
13016
+ let colorClass = "text-indigo-400";
13017
+ if (anc.type === "quest") {
13018
+ Icon = import_fi22.FiCheckSquare;
13019
+ colorClass = "text-amber-400";
13020
+ } else if (anc.type === "version") {
13021
+ Icon = import_fi22.FiGitBranch;
13022
+ colorClass = "text-purple-400";
13023
+ } else if (anc.type === "node") {
13024
+ Icon = import_fi22.FiBox;
13025
+ colorClass = "text-emerald-400";
13026
+ }
13011
13027
  return /* @__PURE__ */ import_react27.default.createElement(
13012
13028
  "div",
13013
13029
  {
13014
- key: anc.ancestry_id,
13030
+ key: `${anc.type || "ancestry"}-${itemId}`,
13015
13031
  className: `
13016
- flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
13017
- ${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
13018
- `,
13019
- title: isValid ? "" : "Esta ancestralidade foi removida ou n\xE3o existe mais."
13032
+ flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
13033
+ ${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
13034
+ `,
13035
+ title: isValid ? "" : "Esta informa\xE7\xE3o n\xE3o est\xE1 mais dispon\xEDvel neste contexto."
13020
13036
  },
13021
- isValid ? (
13022
- // [MANTIDO] Botão Play visível para todos
13037
+ isValid ? /* @__PURE__ */ import_react27.default.createElement(
13038
+ "button",
13039
+ {
13040
+ onClick: () => onPlayAncestry(anc),
13041
+ className: `${colorClass} hover:text-white hover:bg-current/20 p-1 rounded transition-colors flex items-center justify-center`,
13042
+ title: "Focar no cen\xE1rio"
13043
+ },
13044
+ /* @__PURE__ */ import_react27.default.createElement(Icon, { size: 12 }),
13023
13045
  /* @__PURE__ */ import_react27.default.createElement(
13024
- "button",
13046
+ import_fi22.FiPlay,
13025
13047
  {
13026
- onClick: () => onPlayAncestry(anc.ancestry_id),
13027
- className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
13028
- title: "Renderizar no cen\xE1rio"
13029
- },
13030
- /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlay, { size: 10, className: "ml-0.5 fill-current" })
13048
+ size: 8,
13049
+ className: "ml-0.5 fill-current opacity-0 group-hover/card:opacity-100 transition-opacity"
13050
+ }
13031
13051
  )
13032
13052
  ) : /* @__PURE__ */ import_react27.default.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiAlertTriangle, { size: 10 })),
13033
13053
  /* @__PURE__ */ import_react27.default.createElement(
@@ -13045,7 +13065,7 @@ var GroupItem = ({
13045
13065
  ), /* @__PURE__ */ import_react27.default.createElement(
13046
13066
  "button",
13047
13067
  {
13048
- onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
13068
+ onClick: () => onRemoveAncestry(group.id, itemId),
13049
13069
  className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
13050
13070
  title: "Remover men\xE7\xE3o"
13051
13071
  },
@@ -13061,7 +13081,7 @@ var GroupItem = ({
13061
13081
  flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors
13062
13082
  ${isPickingForThisGroup ? "text-indigo-300 animate-pulse" : "text-slate-500 hover:text-indigo-300 hover:bg-indigo-500/10"}
13063
13083
  `,
13064
- title: "Adicionar Ancestralidade a este grupo"
13084
+ title: "Adicionar Men\xE7\xE3o a este grupo"
13065
13085
  },
13066
13086
  isPickingForThisGroup ? /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiCheckCircle, { size: 12 }) : /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiSearch, { size: 12 }),
13067
13087
  isPickingForThisGroup ? "Selecionando..." : "Adicionar"
@@ -13129,7 +13149,6 @@ function AncestryBoard({
13129
13149
  initialGroups = [],
13130
13150
  onSave,
13131
13151
  userRole
13132
- // [NOVO] Recebe a role do usuário
13133
13152
  }) {
13134
13153
  const [searchTerm, setSearchTerm] = (0, import_react27.useState)("");
13135
13154
  const [groups, setGroups] = (0, import_react27.useState)([]);
@@ -13159,13 +13178,39 @@ function AncestryBoard({
13159
13178
  const availableIds = (0, import_react27.useMemo)(() => {
13160
13179
  return new Set(availableAncestries.map((a) => String(a.ancestry_id)));
13161
13180
  }, [availableAncestries]);
13181
+ const allMentionableItems = (0, import_react27.useMemo)(() => {
13182
+ const ancestries = availableAncestries.map((a) => ({
13183
+ id: String(a.ancestry_id),
13184
+ ancestry_id: a.ancestry_id,
13185
+ name: a.name,
13186
+ description: a.description,
13187
+ type: "ancestry",
13188
+ ancestral_node: a.ancestral_node,
13189
+ is_private: a.is_private
13190
+ }));
13191
+ const nodes = availableNodes.map((n) => {
13192
+ let type = "node";
13193
+ if (n.is_quest) type = "quest";
13194
+ else if (n.is_version) type = "version";
13195
+ return {
13196
+ id: String(n.id),
13197
+ name: n.name,
13198
+ description: n.description,
13199
+ type,
13200
+ raw_node: n
13201
+ };
13202
+ });
13203
+ return [...ancestries, ...nodes];
13204
+ }, [availableAncestries, availableNodes]);
13162
13205
  const sanitizeGroups = (groupList) => {
13163
13206
  return groupList.map((g) => ({
13164
13207
  id: g.id,
13165
13208
  text: g.text || "",
13166
13209
  ancestries: (g.ancestries || []).map((a) => ({
13210
+ id: a.id || a.ancestry_id,
13167
13211
  ancestry_id: a.ancestry_id,
13168
- name: a.name
13212
+ name: a.name,
13213
+ type: a.type || "ancestry"
13169
13214
  })),
13170
13215
  children: sanitizeGroups(g.children || [])
13171
13216
  }));
@@ -13206,15 +13251,18 @@ function AncestryBoard({
13206
13251
  }, [isOpen, onClose, pickingGroupId]);
13207
13252
  const filtered = (0, import_react27.useMemo)(() => {
13208
13253
  const term = searchTerm.toLowerCase().trim();
13209
- return availableAncestries.filter((a) => {
13254
+ return allMentionableItems.filter((item) => {
13210
13255
  if (!term) return true;
13211
- const nameMatch = a.name && a.name.toLowerCase().includes(term);
13212
- const descMatch = a.description && a.description.toLowerCase().includes(term);
13213
- const parentName = nodeNamesMap.get(String(a.ancestral_node)) || "";
13214
- const parentMatch = parentName.toLowerCase().includes(term);
13256
+ const nameMatch = item.name && item.name.toLowerCase().includes(term);
13257
+ const descMatch = item.description && item.description.toLowerCase().includes(term);
13258
+ let parentMatch = false;
13259
+ if (item.type === "ancestry") {
13260
+ const parentName = nodeNamesMap.get(String(item.ancestral_node)) || "";
13261
+ parentMatch = parentName.toLowerCase().includes(term);
13262
+ }
13215
13263
  return nameMatch || descMatch || parentMatch;
13216
13264
  });
13217
- }, [availableAncestries, searchTerm, nodeNamesMap]);
13265
+ }, [allMentionableItems, searchTerm, nodeNamesMap]);
13218
13266
  const handleAddRootGroup = () => {
13219
13267
  const newGroup = {
13220
13268
  id: v4_default(),
@@ -13302,17 +13350,18 @@ function AncestryBoard({
13302
13350
  const handleRequestPick = (groupId) => {
13303
13351
  setPickingGroupId((prev) => prev === groupId ? null : groupId);
13304
13352
  };
13305
- const handleSelectAncestry = (ancestry) => {
13353
+ const handleSelectAncestry = (item) => {
13306
13354
  if (pickingGroupId) {
13307
13355
  setGroups((prev) => {
13308
13356
  const addRecursive = (list) => {
13309
13357
  return list.map((g) => {
13310
13358
  if (g.id === pickingGroupId) {
13359
+ const currentId = item.id;
13311
13360
  const exists = g.ancestries.some(
13312
- (a) => a.ancestry_id === ancestry.ancestry_id
13361
+ (a) => (a.id || a.ancestry_id) === currentId && a.type === item.type
13313
13362
  );
13314
13363
  if (exists) return g;
13315
- return { ...g, ancestries: [...g.ancestries, ancestry] };
13364
+ return { ...g, ancestries: [...g.ancestries, item] };
13316
13365
  }
13317
13366
  return { ...g, children: addRecursive(g.children) };
13318
13367
  });
@@ -13321,21 +13370,35 @@ function AncestryBoard({
13321
13370
  });
13322
13371
  setPickingGroupId(null);
13323
13372
  } else {
13324
- const fullAncestry = availableAncestries.find(
13325
- (a) => a.ancestry_id === ancestry.ancestry_id
13326
- ) || ancestry;
13327
- onSelect(fullAncestry);
13373
+ let fullItem = item;
13374
+ if (item.type === "ancestry" || !item.type) {
13375
+ fullItem = availableAncestries.find(
13376
+ (a) => String(a.ancestry_id) === String(item.id || item.ancestry_id)
13377
+ ) || item;
13378
+ } else {
13379
+ fullItem = availableNodes.find(
13380
+ (n) => String(n.id) === String(item.id)
13381
+ ) || item;
13382
+ }
13383
+ onSelect(fullItem);
13328
13384
  }
13329
13385
  };
13330
- const handlePlayFromGroup = (ancestryId) => {
13331
- const fullAncestry = availableAncestries.find(
13332
- (a) => a.ancestry_id === ancestryId
13333
- );
13334
- if (fullAncestry && onSelect) {
13335
- onSelect(fullAncestry);
13386
+ const handlePlayFromGroup = (item) => {
13387
+ let fullItem = item;
13388
+ if (item.type === "ancestry" || !item.type) {
13389
+ fullItem = availableAncestries.find(
13390
+ (a) => String(a.ancestry_id) === String(item.id || item.ancestry_id)
13391
+ ) || item;
13392
+ } else {
13393
+ fullItem = availableNodes.find(
13394
+ (n) => String(n.id) === String(item.id)
13395
+ ) || item;
13396
+ }
13397
+ if (fullItem && onSelect) {
13398
+ onSelect(fullItem);
13336
13399
  }
13337
13400
  };
13338
- const handleRemoveAncestryFromGroup = (groupId, ancestryId) => {
13401
+ const handleRemoveAncestryFromGroup = (groupId, itemId) => {
13339
13402
  setGroups((prev) => {
13340
13403
  const removeRecursive = (list) => {
13341
13404
  return list.map((g) => {
@@ -13343,7 +13406,7 @@ function AncestryBoard({
13343
13406
  return {
13344
13407
  ...g,
13345
13408
  ancestries: g.ancestries.filter(
13346
- (a) => a.ancestry_id !== ancestryId
13409
+ (a) => (a.id || a.ancestry_id) !== itemId
13347
13410
  )
13348
13411
  };
13349
13412
  }
@@ -13406,7 +13469,7 @@ function AncestryBoard({
13406
13469
  "input",
13407
13470
  {
13408
13471
  type: "text",
13409
- placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar ancestralidade...",
13472
+ placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar (Ancestralidades e Nodes)",
13410
13473
  className: `
13411
13474
  w-full rounded-md pl-9 pr-4 py-2 text-sm transition-all focus:outline-none focus:ring-1 focus:ring-indigo-500 border
13412
13475
  ${pickingGroupId ? "bg-indigo-950/30 border-indigo-500/30 text-white placeholder-indigo-300/50" : "bg-slate-950 border-white/10 text-slate-200 placeholder-slate-600"}
@@ -13416,19 +13479,45 @@ function AncestryBoard({
13416
13479
  autoFocus: !pickingGroupId
13417
13480
  }
13418
13481
  ))),
13419
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
13420
- const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
13482
+ /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((item) => {
13421
13483
  const isPicking = !!pickingGroupId;
13484
+ const isQuest = item.type === "quest";
13485
+ const isVersion = item.type === "version";
13486
+ const isNode = item.type === "node";
13487
+ let Icon = import_fi22.FiLayers;
13488
+ let colorClass = "bg-slate-800 text-indigo-400 border-white/5";
13489
+ let pickingColorClass = "bg-indigo-500 text-white border-indigo-400";
13490
+ let hoverClass = "hover:bg-indigo-600/10 hover:border-indigo-500/30";
13491
+ let badge = null;
13492
+ if (isQuest) {
13493
+ Icon = import_fi22.FiCheckSquare;
13494
+ colorClass = "bg-slate-800 text-amber-400 border-white/5";
13495
+ pickingColorClass = "bg-amber-500 text-white border-amber-400";
13496
+ hoverClass = "hover:bg-amber-500/10 hover:border-amber-500/30";
13497
+ badge = "Quest";
13498
+ } else if (isVersion) {
13499
+ Icon = import_fi22.FiGitBranch;
13500
+ colorClass = "bg-slate-800 text-purple-400 border-white/5";
13501
+ pickingColorClass = "bg-purple-500 text-white border-purple-400";
13502
+ hoverClass = "hover:bg-purple-500/10 hover:border-purple-500/30";
13503
+ badge = "Ver";
13504
+ } else if (isNode) {
13505
+ Icon = import_fi22.FiBox;
13506
+ colorClass = "bg-slate-800 text-emerald-400 border-white/5";
13507
+ pickingColorClass = "bg-emerald-500 text-white border-emerald-400";
13508
+ hoverClass = "hover:bg-emerald-500/10 hover:border-emerald-500/30";
13509
+ badge = "Node";
13510
+ }
13422
13511
  return /* @__PURE__ */ import_react27.default.createElement(
13423
13512
  "div",
13424
13513
  {
13425
- key: anc.ancestry_id,
13514
+ key: `${item.type}-${item.id}`,
13426
13515
  onClick: () => {
13427
- if (isPicking) handleSelectAncestry(anc);
13516
+ if (isPicking) handleSelectAncestry(item);
13428
13517
  },
13429
13518
  className: `
13430
13519
  group relative flex items-start gap-3 p-3 text-left rounded-lg border transition-all duration-200
13431
- ${isPicking ? "border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer" : "border-white/5 bg-slate-800/40 hover:bg-indigo-600/10 hover:border-indigo-500/30 cursor-default"}
13520
+ ${isPicking ? `border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer` : `border-white/5 bg-slate-800/40 ${hoverClass} cursor-default`}
13432
13521
  `
13433
13522
  },
13434
13523
  /* @__PURE__ */ import_react27.default.createElement(
@@ -13436,21 +13525,21 @@ function AncestryBoard({
13436
13525
  {
13437
13526
  className: `
13438
13527
  mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
13439
- ${isPicking ? "bg-indigo-500 text-white border-indigo-400" : "bg-slate-800 text-indigo-400 border-white/5 group-hover:bg-indigo-500 group-hover:text-white"}
13528
+ ${isPicking ? pickingColorClass : `${colorClass} group-hover:bg-opacity-80`}
13440
13529
  `
13441
13530
  },
13442
- isPicking ? /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlus, { size: 16 }) : /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiLayers, { size: 14 })
13531
+ isPicking ? /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlus, { size: 16 }) : /* @__PURE__ */ import_react27.default.createElement(Icon, { size: 14 })
13443
13532
  ),
13444
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react27.default.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiCornerUpRight, { size: 10 }), /* @__PURE__ */ import_react27.default.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ import_react27.default.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
13533
+ /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react27.default.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, item.name || "Sem Nome"), badge && /* @__PURE__ */ import_react27.default.createElement("span", { className: `text-[9px] px-1 py-0.5 rounded ${isQuest ? "bg-amber-500/10 text-amber-400" : isVersion ? "bg-purple-500/10 text-purple-400" : "bg-emerald-500/10 text-emerald-400"} border border-current opacity-50` }, badge), item.is_private && /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), item.type === "ancestry" && /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiCornerUpRight, { size: 10 }), /* @__PURE__ */ import_react27.default.createElement("span", { className: "truncate max-w-[120px]" }, nodeNamesMap.get(String(item.ancestral_node)) || "Node Desconhecido")), item.description && /* @__PURE__ */ import_react27.default.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, item.description)),
13445
13534
  !isPicking && /* @__PURE__ */ import_react27.default.createElement(
13446
13535
  "button",
13447
13536
  {
13448
13537
  onClick: (e) => {
13449
13538
  e.stopPropagation();
13450
- handleSelectAncestry(anc);
13539
+ handleSelectAncestry(item);
13451
13540
  },
13452
13541
  className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
13453
- title: "Renderizar Ancestralidade"
13542
+ title: "Renderizar / Focar"
13454
13543
  },
13455
13544
  /* @__PURE__ */ import_react27.default.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlay, { size: 14, className: "ml-0.5" }))
13456
13545
  )
@@ -13672,7 +13761,7 @@ function XViewScene({
13672
13761
  check_user_permission,
13673
13762
  get_view_members
13674
13763
  }) {
13675
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
13764
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
13676
13765
  const { data: session, status } = (0, import_react30.useSession)();
13677
13766
  const router = (0, import_navigation.useRouter)();
13678
13767
  const searchParams = (0, import_navigation.useSearchParams)();
@@ -16055,6 +16144,8 @@ function XViewScene({
16055
16144
  try {
16056
16145
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
16057
16146
  sceneDataRef2.current.quest_counter = currentCounter + 1;
16147
+ sceneDataRef2.current.quest_nodes = sceneFileData.quest_nodes;
16148
+ sceneDataRef2.current.quest_links = sceneFileData.quest_links;
16058
16149
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
16059
16150
  parentFileId: sceneConfigId2,
16060
16151
  ownerId: ownerId2,
@@ -17645,12 +17736,22 @@ function XViewScene({
17645
17736
  setIsAncestryBoardOpen(true);
17646
17737
  }, []);
17647
17738
  const handleSelectAncestryFromBoard = (0, import_react29.useCallback)(
17648
- (ancestry) => {
17739
+ (item) => {
17649
17740
  setIsAncestryBoardOpen(false);
17650
17741
  setIsSidebarOpen(false);
17651
- handleStartReadingAncestry(ancestry);
17742
+ if (item.type === "ancestry" || !item.type) {
17743
+ handleStartReadingAncestry(item);
17744
+ } else {
17745
+ const nodeId = String(item.id);
17746
+ const sceneMesh = stateRef.current.nodeObjects[nodeId];
17747
+ if (sceneMesh) {
17748
+ tweenToTarget(sceneMesh);
17749
+ } else {
17750
+ console.warn("Objeto n\xE3o encontrado na cena para foco:", nodeId);
17751
+ }
17752
+ }
17652
17753
  },
17653
- [handleStartReadingAncestry]
17754
+ [handleStartReadingAncestry, tweenToTarget]
17654
17755
  );
17655
17756
  const handleSaveAncestryBoard = (0, import_react29.useCallback)(
17656
17757
  async (groups) => {
@@ -17679,20 +17780,26 @@ function XViewScene({
17679
17780
  return [...new Set(allTypes)];
17680
17781
  }, [parentDataRef.current, sceneVersion]);
17681
17782
  const searchableDbNodes = (0, import_react29.useMemo)(() => {
17783
+ var _a2;
17682
17784
  if (!parentDataRef.current) {
17683
17785
  return [];
17684
17786
  }
17685
- return Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
17787
+ const datasetsPool = Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
17686
17788
  const datasetName = fileData.dataset_name || `Dataset #${dbId.substring(0, 6)}`;
17687
17789
  return (fileData.nodes || []).map((node) => ({
17688
17790
  ...node,
17689
17791
  dataset_name: datasetName
17690
17792
  }));
17691
- }).filter((node) => {
17692
- var _a2;
17693
- return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
17694
17793
  });
17695
- }, [parentDataRef.current, sceneVersion]);
17794
+ const questsPool = (((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || []).map((node) => ({
17795
+ ...node,
17796
+ dataset_name: "Quests Internas (View)"
17797
+ }));
17798
+ return [...datasetsPool, ...questsPool].filter((node) => {
17799
+ var _a3;
17800
+ return !((_a3 = node.version_node) == null ? void 0 : _a3.is_version);
17801
+ });
17802
+ }, [parentDataRef.current, (_b = sceneDataRef.current) == null ? void 0 : _b.quest_nodes, sceneVersion]);
17696
17803
  const handleAddExistingNode = (0, import_react29.useCallback)(
17697
17804
  (nodeId) => {
17698
17805
  return userActionHandlers.handleAddExistingNodeById(
@@ -17871,9 +17978,9 @@ function XViewScene({
17871
17978
  };
17872
17979
  });
17873
17980
  }, [sceneVersion, isInitialized]);
17874
- const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
17981
+ const sourceNodeDatasetId = creationMode.sourceNodeData ? (_c = stateRef.current.nodeIdToParentFileMap.get(
17875
17982
  String(creationMode.sourceNodeData.id)
17876
- )) == null ? void 0 : _b.parentFileId : null;
17983
+ )) == null ? void 0 : _c.parentFileId : null;
17877
17984
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
17878
17985
  (0, import_react29.useEffect)(() => {
17879
17986
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
@@ -18127,7 +18234,7 @@ function XViewScene({
18127
18234
  onToggle: setIsSidebarOpen,
18128
18235
  userRole: userPermissionRole,
18129
18236
  viewMembers,
18130
- milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
18237
+ milestones: ((_d = sceneDataRef.current) == null ? void 0 : _d.milestones) || [],
18131
18238
  onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
18132
18239
  }
18133
18240
  ),
@@ -18152,8 +18259,8 @@ function XViewScene({
18152
18259
  },
18153
18260
  refEl: formRef,
18154
18261
  existingTypes: existingNodeTypes,
18155
- initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
18156
- sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
18262
+ initialColor: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.color,
18263
+ sourceTypes: (_f = creationMode.sourceNodeData) == null ? void 0 : _f.type,
18157
18264
  onIntensityChange: handleGhostNodeIntensityChange,
18158
18265
  onUploadFile: upload_file_action,
18159
18266
  availableDatasets,
@@ -18182,8 +18289,8 @@ function XViewScene({
18182
18289
  transition: "opacity 200ms ease-out"
18183
18290
  },
18184
18291
  refEl: formRef,
18185
- fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
18186
- fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
18292
+ fixedType: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.type,
18293
+ fixedColor: (_h = versionMode.sourceNodeData) == null ? void 0 : _h.color,
18187
18294
  onUploadFile: upload_file_action,
18188
18295
  availableNodes: allAvailableNodes,
18189
18296
  availableAncestries: allAvailableAncestries
@@ -18211,9 +18318,9 @@ function XViewScene({
18211
18318
  availableNodes: allAvailableNodes,
18212
18319
  availableAncestries: allAvailableAncestries,
18213
18320
  viewName: viewParams == null ? void 0 : viewParams.name,
18214
- questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
18321
+ questCounter: ((_i = sceneDataRef.current) == null ? void 0 : _i.quest_counter) || 1,
18215
18322
  viewMembers,
18216
- milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
18323
+ milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18217
18324
  onUpdateMilestones: handleUpdateMilestones
18218
18325
  }
18219
18326
  ),
@@ -18348,7 +18455,7 @@ function XViewScene({
18348
18455
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
18349
18456
  viewMembers,
18350
18457
  currentUser: session == null ? void 0 : session.user,
18351
- milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18458
+ milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18352
18459
  onUpdateMilestones: handleUpdateMilestones
18353
18460
  }
18354
18461
  ),
@@ -18532,7 +18639,7 @@ function XViewScene({
18532
18639
  {
18533
18640
  isOpen: isMilestoneManagerOpen,
18534
18641
  onClose: () => setIsMilestoneManagerOpen(false),
18535
- milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18642
+ milestones: ((_l = sceneDataRef.current) == null ? void 0 : _l.milestones) || [],
18536
18643
  onUpdateMilestones: handleUpdateMilestones
18537
18644
  }
18538
18645
  ),
@@ -18543,7 +18650,7 @@ function XViewScene({
18543
18650
  onClose: () => setIsImportModalOpen(false),
18544
18651
  onConfirm: handleConfirmImport,
18545
18652
  session,
18546
- parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
18653
+ parentDbs: ((_m = sceneDataRef.current) == null ? void 0 : _m.parent_dbs) || [],
18547
18654
  onFetchAvailableFiles: import_parent_file_modal_get,
18548
18655
  currentViewName: viewParams == null ? void 0 : viewParams.name,
18549
18656
  currentAncestries: ancestryDataRef.current || []
package/dist/index.mjs CHANGED
@@ -2318,6 +2318,8 @@ var userActionHandlers = {
2318
2318
  milestones: sceneDataRef.current.milestones || [],
2319
2319
  quest_counter: sceneDataRef.current.quest_counter || 1
2320
2320
  };
2321
+ sceneDataRef.current.quest_nodes = specificParentData.nodes;
2322
+ sceneDataRef.current.quest_links = specificParentData.links;
2321
2323
  await context.actions.save_view_data(
2322
2324
  context.sceneSaveUrl,
2323
2325
  viewFilePayload
@@ -12993,7 +12995,10 @@ import {
12993
12995
  FiCheckCircle,
12994
12996
  FiLoader as FiLoader5,
12995
12997
  FiX as FiX8,
12996
- FiAlertTriangle
12998
+ FiAlertTriangle,
12999
+ FiCheckSquare as FiCheckSquare3,
13000
+ FiBox,
13001
+ FiGitBranch as FiGitBranch3
12997
13002
  } from "react-icons/fi";
12998
13003
  var GroupItem = ({
12999
13004
  group,
@@ -13051,27 +13056,45 @@ var GroupItem = ({
13051
13056
  }
13052
13057
  ),
13053
13058
  group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React26.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
13054
- const isValid = availableIds.has(String(anc.ancestry_id));
13059
+ const isValid = anc.type === "ancestry" || !anc.type ? availableIds.has(String(anc.ancestry_id || anc.id)) : true;
13060
+ const isAncestry = anc.type === "ancestry" || !anc.type;
13061
+ const itemId = isAncestry ? anc.ancestry_id : anc.id;
13062
+ let Icon = FiLayers6;
13063
+ let colorClass = "text-indigo-400";
13064
+ if (anc.type === "quest") {
13065
+ Icon = FiCheckSquare3;
13066
+ colorClass = "text-amber-400";
13067
+ } else if (anc.type === "version") {
13068
+ Icon = FiGitBranch3;
13069
+ colorClass = "text-purple-400";
13070
+ } else if (anc.type === "node") {
13071
+ Icon = FiBox;
13072
+ colorClass = "text-emerald-400";
13073
+ }
13055
13074
  return /* @__PURE__ */ React26.createElement(
13056
13075
  "div",
13057
13076
  {
13058
- key: anc.ancestry_id,
13077
+ key: `${anc.type || "ancestry"}-${itemId}`,
13059
13078
  className: `
13060
- flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
13061
- ${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
13062
- `,
13063
- title: isValid ? "" : "Esta ancestralidade foi removida ou n\xE3o existe mais."
13079
+ flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
13080
+ ${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
13081
+ `,
13082
+ title: isValid ? "" : "Esta informa\xE7\xE3o n\xE3o est\xE1 mais dispon\xEDvel neste contexto."
13064
13083
  },
13065
- isValid ? (
13066
- // [MANTIDO] Botão Play visível para todos
13084
+ isValid ? /* @__PURE__ */ React26.createElement(
13085
+ "button",
13086
+ {
13087
+ onClick: () => onPlayAncestry(anc),
13088
+ className: `${colorClass} hover:text-white hover:bg-current/20 p-1 rounded transition-colors flex items-center justify-center`,
13089
+ title: "Focar no cen\xE1rio"
13090
+ },
13091
+ /* @__PURE__ */ React26.createElement(Icon, { size: 12 }),
13067
13092
  /* @__PURE__ */ React26.createElement(
13068
- "button",
13093
+ FiPlay,
13069
13094
  {
13070
- onClick: () => onPlayAncestry(anc.ancestry_id),
13071
- className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
13072
- title: "Renderizar no cen\xE1rio"
13073
- },
13074
- /* @__PURE__ */ React26.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
13095
+ size: 8,
13096
+ className: "ml-0.5 fill-current opacity-0 group-hover/card:opacity-100 transition-opacity"
13097
+ }
13075
13098
  )
13076
13099
  ) : /* @__PURE__ */ React26.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React26.createElement(FiAlertTriangle, { size: 10 })),
13077
13100
  /* @__PURE__ */ React26.createElement(
@@ -13089,7 +13112,7 @@ var GroupItem = ({
13089
13112
  ), /* @__PURE__ */ React26.createElement(
13090
13113
  "button",
13091
13114
  {
13092
- onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
13115
+ onClick: () => onRemoveAncestry(group.id, itemId),
13093
13116
  className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
13094
13117
  title: "Remover men\xE7\xE3o"
13095
13118
  },
@@ -13105,7 +13128,7 @@ var GroupItem = ({
13105
13128
  flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors
13106
13129
  ${isPickingForThisGroup ? "text-indigo-300 animate-pulse" : "text-slate-500 hover:text-indigo-300 hover:bg-indigo-500/10"}
13107
13130
  `,
13108
- title: "Adicionar Ancestralidade a este grupo"
13131
+ title: "Adicionar Men\xE7\xE3o a este grupo"
13109
13132
  },
13110
13133
  isPickingForThisGroup ? /* @__PURE__ */ React26.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React26.createElement(FiSearch8, { size: 12 }),
13111
13134
  isPickingForThisGroup ? "Selecionando..." : "Adicionar"
@@ -13173,7 +13196,6 @@ function AncestryBoard({
13173
13196
  initialGroups = [],
13174
13197
  onSave,
13175
13198
  userRole
13176
- // [NOVO] Recebe a role do usuário
13177
13199
  }) {
13178
13200
  const [searchTerm, setSearchTerm] = useState25("");
13179
13201
  const [groups, setGroups] = useState25([]);
@@ -13203,13 +13225,39 @@ function AncestryBoard({
13203
13225
  const availableIds = useMemo11(() => {
13204
13226
  return new Set(availableAncestries.map((a) => String(a.ancestry_id)));
13205
13227
  }, [availableAncestries]);
13228
+ const allMentionableItems = useMemo11(() => {
13229
+ const ancestries = availableAncestries.map((a) => ({
13230
+ id: String(a.ancestry_id),
13231
+ ancestry_id: a.ancestry_id,
13232
+ name: a.name,
13233
+ description: a.description,
13234
+ type: "ancestry",
13235
+ ancestral_node: a.ancestral_node,
13236
+ is_private: a.is_private
13237
+ }));
13238
+ const nodes = availableNodes.map((n) => {
13239
+ let type = "node";
13240
+ if (n.is_quest) type = "quest";
13241
+ else if (n.is_version) type = "version";
13242
+ return {
13243
+ id: String(n.id),
13244
+ name: n.name,
13245
+ description: n.description,
13246
+ type,
13247
+ raw_node: n
13248
+ };
13249
+ });
13250
+ return [...ancestries, ...nodes];
13251
+ }, [availableAncestries, availableNodes]);
13206
13252
  const sanitizeGroups = (groupList) => {
13207
13253
  return groupList.map((g) => ({
13208
13254
  id: g.id,
13209
13255
  text: g.text || "",
13210
13256
  ancestries: (g.ancestries || []).map((a) => ({
13257
+ id: a.id || a.ancestry_id,
13211
13258
  ancestry_id: a.ancestry_id,
13212
- name: a.name
13259
+ name: a.name,
13260
+ type: a.type || "ancestry"
13213
13261
  })),
13214
13262
  children: sanitizeGroups(g.children || [])
13215
13263
  }));
@@ -13250,15 +13298,18 @@ function AncestryBoard({
13250
13298
  }, [isOpen, onClose, pickingGroupId]);
13251
13299
  const filtered = useMemo11(() => {
13252
13300
  const term = searchTerm.toLowerCase().trim();
13253
- return availableAncestries.filter((a) => {
13301
+ return allMentionableItems.filter((item) => {
13254
13302
  if (!term) return true;
13255
- const nameMatch = a.name && a.name.toLowerCase().includes(term);
13256
- const descMatch = a.description && a.description.toLowerCase().includes(term);
13257
- const parentName = nodeNamesMap.get(String(a.ancestral_node)) || "";
13258
- const parentMatch = parentName.toLowerCase().includes(term);
13303
+ const nameMatch = item.name && item.name.toLowerCase().includes(term);
13304
+ const descMatch = item.description && item.description.toLowerCase().includes(term);
13305
+ let parentMatch = false;
13306
+ if (item.type === "ancestry") {
13307
+ const parentName = nodeNamesMap.get(String(item.ancestral_node)) || "";
13308
+ parentMatch = parentName.toLowerCase().includes(term);
13309
+ }
13259
13310
  return nameMatch || descMatch || parentMatch;
13260
13311
  });
13261
- }, [availableAncestries, searchTerm, nodeNamesMap]);
13312
+ }, [allMentionableItems, searchTerm, nodeNamesMap]);
13262
13313
  const handleAddRootGroup = () => {
13263
13314
  const newGroup = {
13264
13315
  id: v4_default(),
@@ -13346,17 +13397,18 @@ function AncestryBoard({
13346
13397
  const handleRequestPick = (groupId) => {
13347
13398
  setPickingGroupId((prev) => prev === groupId ? null : groupId);
13348
13399
  };
13349
- const handleSelectAncestry = (ancestry) => {
13400
+ const handleSelectAncestry = (item) => {
13350
13401
  if (pickingGroupId) {
13351
13402
  setGroups((prev) => {
13352
13403
  const addRecursive = (list) => {
13353
13404
  return list.map((g) => {
13354
13405
  if (g.id === pickingGroupId) {
13406
+ const currentId = item.id;
13355
13407
  const exists = g.ancestries.some(
13356
- (a) => a.ancestry_id === ancestry.ancestry_id
13408
+ (a) => (a.id || a.ancestry_id) === currentId && a.type === item.type
13357
13409
  );
13358
13410
  if (exists) return g;
13359
- return { ...g, ancestries: [...g.ancestries, ancestry] };
13411
+ return { ...g, ancestries: [...g.ancestries, item] };
13360
13412
  }
13361
13413
  return { ...g, children: addRecursive(g.children) };
13362
13414
  });
@@ -13365,21 +13417,35 @@ function AncestryBoard({
13365
13417
  });
13366
13418
  setPickingGroupId(null);
13367
13419
  } else {
13368
- const fullAncestry = availableAncestries.find(
13369
- (a) => a.ancestry_id === ancestry.ancestry_id
13370
- ) || ancestry;
13371
- onSelect(fullAncestry);
13420
+ let fullItem = item;
13421
+ if (item.type === "ancestry" || !item.type) {
13422
+ fullItem = availableAncestries.find(
13423
+ (a) => String(a.ancestry_id) === String(item.id || item.ancestry_id)
13424
+ ) || item;
13425
+ } else {
13426
+ fullItem = availableNodes.find(
13427
+ (n) => String(n.id) === String(item.id)
13428
+ ) || item;
13429
+ }
13430
+ onSelect(fullItem);
13372
13431
  }
13373
13432
  };
13374
- const handlePlayFromGroup = (ancestryId) => {
13375
- const fullAncestry = availableAncestries.find(
13376
- (a) => a.ancestry_id === ancestryId
13377
- );
13378
- if (fullAncestry && onSelect) {
13379
- onSelect(fullAncestry);
13433
+ const handlePlayFromGroup = (item) => {
13434
+ let fullItem = item;
13435
+ if (item.type === "ancestry" || !item.type) {
13436
+ fullItem = availableAncestries.find(
13437
+ (a) => String(a.ancestry_id) === String(item.id || item.ancestry_id)
13438
+ ) || item;
13439
+ } else {
13440
+ fullItem = availableNodes.find(
13441
+ (n) => String(n.id) === String(item.id)
13442
+ ) || item;
13443
+ }
13444
+ if (fullItem && onSelect) {
13445
+ onSelect(fullItem);
13380
13446
  }
13381
13447
  };
13382
- const handleRemoveAncestryFromGroup = (groupId, ancestryId) => {
13448
+ const handleRemoveAncestryFromGroup = (groupId, itemId) => {
13383
13449
  setGroups((prev) => {
13384
13450
  const removeRecursive = (list) => {
13385
13451
  return list.map((g) => {
@@ -13387,7 +13453,7 @@ function AncestryBoard({
13387
13453
  return {
13388
13454
  ...g,
13389
13455
  ancestries: g.ancestries.filter(
13390
- (a) => a.ancestry_id !== ancestryId
13456
+ (a) => (a.id || a.ancestry_id) !== itemId
13391
13457
  )
13392
13458
  };
13393
13459
  }
@@ -13450,7 +13516,7 @@ function AncestryBoard({
13450
13516
  "input",
13451
13517
  {
13452
13518
  type: "text",
13453
- placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar ancestralidade...",
13519
+ placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar (Ancestralidades e Nodes)",
13454
13520
  className: `
13455
13521
  w-full rounded-md pl-9 pr-4 py-2 text-sm transition-all focus:outline-none focus:ring-1 focus:ring-indigo-500 border
13456
13522
  ${pickingGroupId ? "bg-indigo-950/30 border-indigo-500/30 text-white placeholder-indigo-300/50" : "bg-slate-950 border-white/10 text-slate-200 placeholder-slate-600"}
@@ -13460,19 +13526,45 @@ function AncestryBoard({
13460
13526
  autoFocus: !pickingGroupId
13461
13527
  }
13462
13528
  ))),
13463
- /* @__PURE__ */ React26.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
13464
- const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
13529
+ /* @__PURE__ */ React26.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((item) => {
13465
13530
  const isPicking = !!pickingGroupId;
13531
+ const isQuest = item.type === "quest";
13532
+ const isVersion = item.type === "version";
13533
+ const isNode = item.type === "node";
13534
+ let Icon = FiLayers6;
13535
+ let colorClass = "bg-slate-800 text-indigo-400 border-white/5";
13536
+ let pickingColorClass = "bg-indigo-500 text-white border-indigo-400";
13537
+ let hoverClass = "hover:bg-indigo-600/10 hover:border-indigo-500/30";
13538
+ let badge = null;
13539
+ if (isQuest) {
13540
+ Icon = FiCheckSquare3;
13541
+ colorClass = "bg-slate-800 text-amber-400 border-white/5";
13542
+ pickingColorClass = "bg-amber-500 text-white border-amber-400";
13543
+ hoverClass = "hover:bg-amber-500/10 hover:border-amber-500/30";
13544
+ badge = "Quest";
13545
+ } else if (isVersion) {
13546
+ Icon = FiGitBranch3;
13547
+ colorClass = "bg-slate-800 text-purple-400 border-white/5";
13548
+ pickingColorClass = "bg-purple-500 text-white border-purple-400";
13549
+ hoverClass = "hover:bg-purple-500/10 hover:border-purple-500/30";
13550
+ badge = "Ver";
13551
+ } else if (isNode) {
13552
+ Icon = FiBox;
13553
+ colorClass = "bg-slate-800 text-emerald-400 border-white/5";
13554
+ pickingColorClass = "bg-emerald-500 text-white border-emerald-400";
13555
+ hoverClass = "hover:bg-emerald-500/10 hover:border-emerald-500/30";
13556
+ badge = "Node";
13557
+ }
13466
13558
  return /* @__PURE__ */ React26.createElement(
13467
13559
  "div",
13468
13560
  {
13469
- key: anc.ancestry_id,
13561
+ key: `${item.type}-${item.id}`,
13470
13562
  onClick: () => {
13471
- if (isPicking) handleSelectAncestry(anc);
13563
+ if (isPicking) handleSelectAncestry(item);
13472
13564
  },
13473
13565
  className: `
13474
13566
  group relative flex items-start gap-3 p-3 text-left rounded-lg border transition-all duration-200
13475
- ${isPicking ? "border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer" : "border-white/5 bg-slate-800/40 hover:bg-indigo-600/10 hover:border-indigo-500/30 cursor-default"}
13567
+ ${isPicking ? `border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer` : `border-white/5 bg-slate-800/40 ${hoverClass} cursor-default`}
13476
13568
  `
13477
13569
  },
13478
13570
  /* @__PURE__ */ React26.createElement(
@@ -13480,21 +13572,21 @@ function AncestryBoard({
13480
13572
  {
13481
13573
  className: `
13482
13574
  mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
13483
- ${isPicking ? "bg-indigo-500 text-white border-indigo-400" : "bg-slate-800 text-indigo-400 border-white/5 group-hover:bg-indigo-500 group-hover:text-white"}
13575
+ ${isPicking ? pickingColorClass : `${colorClass} group-hover:bg-opacity-80`}
13484
13576
  `
13485
13577
  },
13486
- isPicking ? /* @__PURE__ */ React26.createElement(FiPlus10, { size: 16 }) : /* @__PURE__ */ React26.createElement(FiLayers6, { size: 14 })
13578
+ isPicking ? /* @__PURE__ */ React26.createElement(FiPlus10, { size: 16 }) : /* @__PURE__ */ React26.createElement(Icon, { size: 14 })
13487
13579
  ),
13488
- /* @__PURE__ */ React26.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React26.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React26.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React26.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React26.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React26.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React26.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React26.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
13580
+ /* @__PURE__ */ React26.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React26.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React26.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, item.name || "Sem Nome"), badge && /* @__PURE__ */ React26.createElement("span", { className: `text-[9px] px-1 py-0.5 rounded ${isQuest ? "bg-amber-500/10 text-amber-400" : isVersion ? "bg-purple-500/10 text-purple-400" : "bg-emerald-500/10 text-emerald-400"} border border-current opacity-50` }, badge), item.is_private && /* @__PURE__ */ React26.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), item.type === "ancestry" && /* @__PURE__ */ React26.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React26.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React26.createElement("span", { className: "truncate max-w-[120px]" }, nodeNamesMap.get(String(item.ancestral_node)) || "Node Desconhecido")), item.description && /* @__PURE__ */ React26.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, item.description)),
13489
13581
  !isPicking && /* @__PURE__ */ React26.createElement(
13490
13582
  "button",
13491
13583
  {
13492
13584
  onClick: (e) => {
13493
13585
  e.stopPropagation();
13494
- handleSelectAncestry(anc);
13586
+ handleSelectAncestry(item);
13495
13587
  },
13496
13588
  className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
13497
- title: "Renderizar Ancestralidade"
13589
+ title: "Renderizar / Focar"
13498
13590
  },
13499
13591
  /* @__PURE__ */ React26.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React26.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
13500
13592
  )
@@ -13716,7 +13808,7 @@ function XViewScene({
13716
13808
  check_user_permission,
13717
13809
  get_view_members
13718
13810
  }) {
13719
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
13811
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
13720
13812
  const { data: session, status } = useSession();
13721
13813
  const router = useRouter();
13722
13814
  const searchParams = useSearchParams();
@@ -16099,6 +16191,8 @@ function XViewScene({
16099
16191
  try {
16100
16192
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
16101
16193
  sceneDataRef2.current.quest_counter = currentCounter + 1;
16194
+ sceneDataRef2.current.quest_nodes = sceneFileData.quest_nodes;
16195
+ sceneDataRef2.current.quest_links = sceneFileData.quest_links;
16102
16196
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
16103
16197
  parentFileId: sceneConfigId2,
16104
16198
  ownerId: ownerId2,
@@ -17689,12 +17783,22 @@ function XViewScene({
17689
17783
  setIsAncestryBoardOpen(true);
17690
17784
  }, []);
17691
17785
  const handleSelectAncestryFromBoard = useCallback4(
17692
- (ancestry) => {
17786
+ (item) => {
17693
17787
  setIsAncestryBoardOpen(false);
17694
17788
  setIsSidebarOpen(false);
17695
- handleStartReadingAncestry(ancestry);
17789
+ if (item.type === "ancestry" || !item.type) {
17790
+ handleStartReadingAncestry(item);
17791
+ } else {
17792
+ const nodeId = String(item.id);
17793
+ const sceneMesh = stateRef.current.nodeObjects[nodeId];
17794
+ if (sceneMesh) {
17795
+ tweenToTarget(sceneMesh);
17796
+ } else {
17797
+ console.warn("Objeto n\xE3o encontrado na cena para foco:", nodeId);
17798
+ }
17799
+ }
17696
17800
  },
17697
- [handleStartReadingAncestry]
17801
+ [handleStartReadingAncestry, tweenToTarget]
17698
17802
  );
17699
17803
  const handleSaveAncestryBoard = useCallback4(
17700
17804
  async (groups) => {
@@ -17723,20 +17827,26 @@ function XViewScene({
17723
17827
  return [...new Set(allTypes)];
17724
17828
  }, [parentDataRef.current, sceneVersion]);
17725
17829
  const searchableDbNodes = useMemo12(() => {
17830
+ var _a2;
17726
17831
  if (!parentDataRef.current) {
17727
17832
  return [];
17728
17833
  }
17729
- return Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
17834
+ const datasetsPool = Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
17730
17835
  const datasetName = fileData.dataset_name || `Dataset #${dbId.substring(0, 6)}`;
17731
17836
  return (fileData.nodes || []).map((node) => ({
17732
17837
  ...node,
17733
17838
  dataset_name: datasetName
17734
17839
  }));
17735
- }).filter((node) => {
17736
- var _a2;
17737
- return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
17738
17840
  });
17739
- }, [parentDataRef.current, sceneVersion]);
17841
+ const questsPool = (((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || []).map((node) => ({
17842
+ ...node,
17843
+ dataset_name: "Quests Internas (View)"
17844
+ }));
17845
+ return [...datasetsPool, ...questsPool].filter((node) => {
17846
+ var _a3;
17847
+ return !((_a3 = node.version_node) == null ? void 0 : _a3.is_version);
17848
+ });
17849
+ }, [parentDataRef.current, (_b = sceneDataRef.current) == null ? void 0 : _b.quest_nodes, sceneVersion]);
17740
17850
  const handleAddExistingNode = useCallback4(
17741
17851
  (nodeId) => {
17742
17852
  return userActionHandlers.handleAddExistingNodeById(
@@ -17915,9 +18025,9 @@ function XViewScene({
17915
18025
  };
17916
18026
  });
17917
18027
  }, [sceneVersion, isInitialized]);
17918
- const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
18028
+ const sourceNodeDatasetId = creationMode.sourceNodeData ? (_c = stateRef.current.nodeIdToParentFileMap.get(
17919
18029
  String(creationMode.sourceNodeData.id)
17920
- )) == null ? void 0 : _b.parentFileId : null;
18030
+ )) == null ? void 0 : _c.parentFileId : null;
17921
18031
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
17922
18032
  useEffect22(() => {
17923
18033
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
@@ -18171,7 +18281,7 @@ function XViewScene({
18171
18281
  onToggle: setIsSidebarOpen,
18172
18282
  userRole: userPermissionRole,
18173
18283
  viewMembers,
18174
- milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
18284
+ milestones: ((_d = sceneDataRef.current) == null ? void 0 : _d.milestones) || [],
18175
18285
  onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
18176
18286
  }
18177
18287
  ),
@@ -18196,8 +18306,8 @@ function XViewScene({
18196
18306
  },
18197
18307
  refEl: formRef,
18198
18308
  existingTypes: existingNodeTypes,
18199
- initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
18200
- sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
18309
+ initialColor: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.color,
18310
+ sourceTypes: (_f = creationMode.sourceNodeData) == null ? void 0 : _f.type,
18201
18311
  onIntensityChange: handleGhostNodeIntensityChange,
18202
18312
  onUploadFile: upload_file_action,
18203
18313
  availableDatasets,
@@ -18226,8 +18336,8 @@ function XViewScene({
18226
18336
  transition: "opacity 200ms ease-out"
18227
18337
  },
18228
18338
  refEl: formRef,
18229
- fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
18230
- fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
18339
+ fixedType: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.type,
18340
+ fixedColor: (_h = versionMode.sourceNodeData) == null ? void 0 : _h.color,
18231
18341
  onUploadFile: upload_file_action,
18232
18342
  availableNodes: allAvailableNodes,
18233
18343
  availableAncestries: allAvailableAncestries
@@ -18255,9 +18365,9 @@ function XViewScene({
18255
18365
  availableNodes: allAvailableNodes,
18256
18366
  availableAncestries: allAvailableAncestries,
18257
18367
  viewName: viewParams == null ? void 0 : viewParams.name,
18258
- questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
18368
+ questCounter: ((_i = sceneDataRef.current) == null ? void 0 : _i.quest_counter) || 1,
18259
18369
  viewMembers,
18260
- milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
18370
+ milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18261
18371
  onUpdateMilestones: handleUpdateMilestones
18262
18372
  }
18263
18373
  ),
@@ -18392,7 +18502,7 @@ function XViewScene({
18392
18502
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
18393
18503
  viewMembers,
18394
18504
  currentUser: session == null ? void 0 : session.user,
18395
- milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18505
+ milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18396
18506
  onUpdateMilestones: handleUpdateMilestones
18397
18507
  }
18398
18508
  ),
@@ -18576,7 +18686,7 @@ function XViewScene({
18576
18686
  {
18577
18687
  isOpen: isMilestoneManagerOpen,
18578
18688
  onClose: () => setIsMilestoneManagerOpen(false),
18579
- milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18689
+ milestones: ((_l = sceneDataRef.current) == null ? void 0 : _l.milestones) || [],
18580
18690
  onUpdateMilestones: handleUpdateMilestones
18581
18691
  }
18582
18692
  ),
@@ -18587,7 +18697,7 @@ function XViewScene({
18587
18697
  onClose: () => setIsImportModalOpen(false),
18588
18698
  onConfirm: handleConfirmImport,
18589
18699
  session,
18590
- parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
18700
+ parentDbs: ((_m = sceneDataRef.current) == null ? void 0 : _m.parent_dbs) || [],
18591
18701
  onFetchAvailableFiles: import_parent_file_modal_get,
18592
18702
  currentViewName: viewParams == null ? void 0 : viewParams.name,
18593
18703
  currentAncestries: ancestryDataRef.current || []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.5",
3
+ "version": "1.2.6-dev.1",
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",