@lv-x-software-house/x_view 1.2.6-dev.3 → 1.2.6-dev.30

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 +1585 -851
  2. package/dist/index.mjs +1506 -791
  3. package/package.json +4 -22
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -30,14 +29,24 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
29
  // src/index.js
31
30
  var index_exports = {};
32
31
  __export(index_exports, {
33
- XViewScene: () => XViewScene
32
+ XViewScene: () => XViewScene,
33
+ delete_uploaded_file_logic: () => delete_uploaded_file_logic,
34
+ get_ancestry_file_logic: () => get_ancestry_file_logic,
35
+ get_boards_logic: () => get_boards_logic,
36
+ get_scene_view_data_logic: () => get_scene_view_data_logic,
37
+ get_single_parent_file_logic: () => get_single_parent_file_logic,
38
+ get_view_members_logic: () => get_view_members_logic,
39
+ import_parent_file_modal_get_logic: () => import_parent_file_modal_get_logic,
40
+ save_boards_logic: () => save_boards_logic,
41
+ save_view_data_logic: () => save_view_data_logic,
42
+ x_view_add_new_parent_file_to_scene_at_firebase: () => x_view_add_new_parent_file_to_scene_at_firebase
34
43
  });
35
44
  module.exports = __toCommonJS(index_exports);
36
45
 
37
46
  // src/XViewScene.jsx
38
- var import_react32 = __toESM(require("react"));
47
+ var import_react31 = __toESM(require("react"));
39
48
  var import_navigation = require("next/navigation");
40
- var import_react33 = require("next-auth/react");
49
+ var import_react32 = require("next-auth/react");
41
50
  var import_crypto_js = __toESM(require("crypto-js"));
42
51
  var THREE3 = __toESM(require("three"));
43
52
  var import_OrbitControls = require("three/examples/jsm/controls/OrbitControls.js");
@@ -68,8 +77,8 @@ function defineAbilityFor(role) {
68
77
  can("read", "Versioning");
69
78
  can("read", "Node");
70
79
  can("read", "Scene");
71
- can("read", "AncestryBoard");
72
- can("read", "AncestryGroup");
80
+ can("read", "Boards");
81
+ can("read", "BoardGroups");
73
82
  can("dismiss", "Node");
74
83
  cannot("update", "Scene");
75
84
  cannot("import", "File");
@@ -82,10 +91,10 @@ function defineAbilityFor(role) {
82
91
  cannot("create", "Ancestry");
83
92
  cannot("update", "Ancestry");
84
93
  cannot("delete", "Ancestry");
85
- cannot("create", "AncestryGroup");
86
- cannot("update", "AncestryGroup");
87
- cannot("delete", "AncestryGroup");
88
- cannot("manage", "AncestryBoard");
94
+ cannot("create", "BoardGroups");
95
+ cannot("update", "BoardGroups");
96
+ cannot("delete", "BoardGroups");
97
+ cannot("manage", "Boards");
89
98
  cannot("update", "Node");
90
99
  break;
91
100
  case "link_viewer":
@@ -94,8 +103,8 @@ function defineAbilityFor(role) {
94
103
  can("read", "Versioning");
95
104
  cannot("read", "Scene");
96
105
  cannot("read", "Connection");
97
- cannot("read", "AncestryBoard");
98
- cannot("read", "AncestryGroup");
106
+ cannot("read", "Boards");
107
+ cannot("read", "BoardGroups");
99
108
  cannot("dismiss", "Node");
100
109
  cannot("manage", "all");
101
110
  break;
@@ -1083,6 +1092,8 @@ var userActionHandlers = {
1083
1092
  if (isCrossDataset) {
1084
1093
  graphDataRef.current[finalTargetDatasetId] = targetDataToUpdate;
1085
1094
  }
1095
+ if (sceneDataRef.current.parent_dbs.some((db) => String(db.db_id) === String(sourceParentInfo.parentFileId))) {
1096
+ }
1086
1097
  const finalPosition = stateRef.current.ghostElements.node.position.clone();
1087
1098
  addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
1088
1099
  stateRef.current.nodeIdToParentFileMap.set(String(newNode.id), {
@@ -1281,6 +1292,9 @@ var userActionHandlers = {
1281
1292
  );
1282
1293
  }
1283
1294
  graphDataRef.current[parentFileId] = specificParentData;
1295
+ if (isView && parentFileId === context.sceneConfigId) {
1296
+ sceneDataRef.current.quest_nodes = [...specificParentData.nodes];
1297
+ }
1284
1298
  const finalPosition = stateRef.current.ghostElements.node.position.clone();
1285
1299
  addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
1286
1300
  setters.setSceneVersion((v) => v + 1);
@@ -2300,8 +2314,6 @@ var userActionHandlers = {
2300
2314
  milestones: sceneDataRef.current.milestones || [],
2301
2315
  quest_counter: sceneDataRef.current.quest_counter || 1
2302
2316
  };
2303
- sceneDataRef.current.quest_nodes = specificParentData.nodes;
2304
- sceneDataRef.current.quest_links = specificParentData.links;
2305
2317
  await context.actions.save_view_data(
2306
2318
  context.sceneSaveUrl,
2307
2319
  viewFilePayload
@@ -2314,6 +2326,10 @@ var userActionHandlers = {
2314
2326
  );
2315
2327
  }
2316
2328
  graphDataRef.current[parentFileId] = specificParentData;
2329
+ if (isView && parentFileId === context.sceneConfigId) {
2330
+ sceneDataRef.current.quest_nodes = [...specificParentData.nodes];
2331
+ sceneDataRef.current.quest_counter = specificParentData.quest_counter || sceneDataRef.current.quest_counter;
2332
+ }
2317
2333
  updateExistingNodeVisuals(stateRef.current, nodeToSave);
2318
2334
  setters.setSceneVersion((v) => v + 1);
2319
2335
  if (!keepOpen) {
@@ -3866,7 +3882,7 @@ function XViewSidebar({
3866
3882
  importSuccessMessage = "",
3867
3883
  onActivateTimeline = () => {
3868
3884
  },
3869
- onOpenAncestryBoard = () => {
3885
+ onOpenBoards = () => {
3870
3886
  },
3871
3887
  viewType,
3872
3888
  viewName,
@@ -4367,12 +4383,12 @@ function XViewSidebar({
4367
4383
  ), /* @__PURE__ */ import_react3.default.createElement(
4368
4384
  "button",
4369
4385
  {
4370
- onClick: onOpenAncestryBoard,
4386
+ onClick: onOpenBoards,
4371
4387
  className: buttonBaseClass,
4372
- title: "Abrir painel de Ancestralidades"
4388
+ title: "Abrir painel de Boards"
4373
4389
  },
4374
- /* @__PURE__ */ import_react3.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_react3.default.createElement("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }), /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "2 17 12 22 22 17" }), /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "2 12 12 17 22 12" })),
4375
- "Ancestry Board"
4390
+ /* @__PURE__ */ import_react3.default.createElement(import_fi2.FiLayers, { size: 16 }),
4391
+ "Boards"
4376
4392
  )), /* @__PURE__ */ import_react3.default.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-3" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Milestones"), /* @__PURE__ */ import_react3.default.createElement(
4377
4393
  "button",
4378
4394
  {
@@ -12902,559 +12918,787 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
12902
12918
  );
12903
12919
  }
12904
12920
 
12905
- // src/components/AncestryBoard.jsx
12906
- var import_react30 = __toESM(require("react"));
12921
+ // src/components/Boards.jsx
12922
+ var import_react29 = __toESM(require("react"));
12907
12923
  var import_fi23 = require("react-icons/fi");
12908
12924
  var import_uuid11 = require("uuid");
12909
12925
 
12910
- // src/components/MentionEditor.jsx
12926
+ // src/components/RichGroupEditor.jsx
12911
12927
  var import_react28 = __toESM(require("react"));
12912
- var import_react29 = require("@tiptap/react");
12913
- var import_starter_kit = __toESM(require("@tiptap/starter-kit"));
12914
- var import_extension_mention = __toESM(require("@tiptap/extension-mention"));
12915
- var import_tippy = __toESM(require("tippy.js"));
12916
12928
 
12917
- // src/components/MentionList.jsx
12929
+ // src/components/MentionPopover.jsx
12918
12930
  var import_react27 = __toESM(require("react"));
12919
12931
  var import_fi22 = require("react-icons/fi");
12920
- var MentionList = (0, import_react27.forwardRef)((props, ref) => {
12921
- const [selectedIndex, setSelectedIndex] = (0, import_react27.useState)(0);
12922
- const selectItem = (index) => {
12923
- const item = props.items[index];
12924
- if (item) {
12925
- props.command({ id: item.id, label: item.name, type: item.type });
12926
- }
12927
- };
12928
- const upHandler = () => {
12929
- setSelectedIndex(
12930
- (selectedIndex + props.items.length - 1) % props.items.length
12931
- );
12932
- };
12933
- const downHandler = () => {
12934
- setSelectedIndex((selectedIndex + 1) % props.items.length);
12935
- };
12936
- const enterHandler = () => {
12937
- selectItem(selectedIndex);
12938
- };
12939
- (0, import_react27.useEffect)(() => setSelectedIndex(0), [props.items]);
12940
- (0, import_react27.useImperativeHandle)(ref, () => ({
12941
- onKeyDown: ({ event }) => {
12942
- if (event.key === "ArrowUp") {
12943
- upHandler();
12944
- return true;
12945
- }
12946
- if (event.key === "ArrowDown") {
12947
- downHandler();
12948
- return true;
12949
- }
12950
- if (event.key === "Enter") {
12951
- enterHandler();
12952
- return true;
12932
+ var TYPE_CONFIG = {
12933
+ ancestry: { Icon: import_fi22.FiLayers, color: "text-indigo-400", label: "Ancestralidade" },
12934
+ quest: { Icon: import_fi22.FiCheckSquare, color: "text-emerald-400", label: "Quest" },
12935
+ version: { Icon: import_fi22.FiGitBranch, color: "text-amber-400", label: "Vers\xE3o" },
12936
+ node: { Icon: import_fi22.FiBox, color: "text-slate-400", label: "Node" }
12937
+ };
12938
+ function MentionPopover({ query, items, position, onSelect, onClose }) {
12939
+ const [activeIndex, setActiveIndex] = (0, import_react27.useState)(0);
12940
+ const listRef = (0, import_react27.useRef)(null);
12941
+ const filtered = (0, import_react27.useMemo)(() => {
12942
+ const term = (query || "").toLowerCase().trim();
12943
+ if (!term) return items.slice(0, 8);
12944
+ return items.filter(
12945
+ (item) => (item.searchLabel || "").toLowerCase().includes(term) || (item.searchDesc || "").toLowerCase().includes(term)
12946
+ ).slice(0, 8);
12947
+ }, [items, query]);
12948
+ (0, import_react27.useEffect)(() => {
12949
+ setActiveIndex(0);
12950
+ }, [query]);
12951
+ (0, import_react27.useEffect)(() => {
12952
+ const handleKeyDown = (e) => {
12953
+ if (e.key === "ArrowDown") {
12954
+ e.preventDefault();
12955
+ setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
12956
+ } else if (e.key === "ArrowUp") {
12957
+ e.preventDefault();
12958
+ setActiveIndex((i) => Math.max(i - 1, 0));
12959
+ } else if (e.key === "Enter" || e.key === "Tab") {
12960
+ e.preventDefault();
12961
+ if (filtered[activeIndex]) onSelect(filtered[activeIndex]);
12962
+ } else if (e.key === "Escape") {
12963
+ e.preventDefault();
12964
+ e.stopPropagation();
12965
+ e.stopImmediatePropagation();
12966
+ onClose();
12953
12967
  }
12954
- return false;
12955
- }
12956
- }));
12957
- return /* @__PURE__ */ import_react27.default.createElement("div", { className: "z-[3000] bg-slate-900 border border-white/10 rounded-lg shadow-2xl overflow-hidden min-w-[280px] max-w-[400px] animate-in fade-in zoom-in-95 duration-200" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "p-2 border-b border-white/5 bg-slate-950/50 flex items-center gap-2" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiSearch, { className: "text-indigo-400", size: 14 }), /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[10px] uppercase tracking-wider font-bold text-slate-500" }, "Mencionar Recurso")), /* @__PURE__ */ import_react27.default.createElement("div", { className: "p-1 max-h-[300px] overflow-y-auto custom-scrollbar" }, props.items.length ? props.items.map((item, index) => {
12958
- const isQuest = item.type === "quest";
12959
- const isVersion = item.type === "version";
12960
- const isNode = item.type === "node";
12961
- let Icon = import_fi22.FiLayers;
12962
- let colorClass = "text-indigo-400";
12963
- let badgeText = "Ancestralidade";
12964
- if (isQuest) {
12965
- Icon = import_fi22.FiCheckSquare;
12966
- colorClass = "text-amber-400";
12967
- badgeText = "Quest";
12968
- } else if (isVersion) {
12969
- Icon = import_fi22.FiGitBranch;
12970
- colorClass = "text-purple-400";
12971
- badgeText = "Vers\xE3o";
12972
- } else if (isNode) {
12973
- Icon = import_fi22.FiBox;
12974
- colorClass = "text-emerald-400";
12975
- badgeText = "Node";
12976
- }
12977
- return /* @__PURE__ */ import_react27.default.createElement(
12978
- "button",
12979
- {
12980
- className: `
12981
- w-full flex items-center gap-3 px-3 py-2 text-left rounded-md transition-all
12982
- ${index === selectedIndex ? "bg-indigo-500/20 border border-indigo-500/30 text-white" : "text-slate-400 hover:bg-white/5 border border-transparent"}
12983
- `,
12984
- key: item.id,
12985
- onClick: () => selectItem(index)
12986
- },
12987
- /* @__PURE__ */ import_react27.default.createElement("div", { className: `shrink-0 w-8 h-8 rounded border border-white/5 flex items-center justify-center bg-slate-800/50 ${colorClass}` }, /* @__PURE__ */ import_react27.default.createElement(Icon, { size: 14 })),
12988
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-sm font-medium truncate" }, item.name), /* @__PURE__ */ import_react27.default.createElement("span", { className: `text-[9px] px-1 py-0.5 rounded border border-current opacity-60 ${colorClass}` }, badgeText)))
12989
- );
12990
- }) : /* @__PURE__ */ import_react27.default.createElement("div", { className: "p-4 text-center text-slate-500 text-sm italic" }, "Nenhum resultado encontrado...")));
12991
- });
12992
- MentionList.displayName = "MentionList";
12993
- var MentionList_default = MentionList;
12968
+ };
12969
+ window.addEventListener("keydown", handleKeyDown, true);
12970
+ return () => window.removeEventListener("keydown", handleKeyDown, true);
12971
+ }, [filtered, activeIndex, onSelect, onClose]);
12972
+ (0, import_react27.useEffect)(() => {
12973
+ if (listRef.current) {
12974
+ const el = listRef.current.children[activeIndex];
12975
+ if (el) el.scrollIntoView({ block: "nearest" });
12976
+ }
12977
+ }, [activeIndex]);
12978
+ return /* @__PURE__ */ import_react27.default.createElement(
12979
+ "div",
12980
+ {
12981
+ style: { top: position.top, left: position.left, position: "fixed", zIndex: 9999 },
12982
+ className: "bg-slate-900 border border-white/10 rounded-xl shadow-2xl py-1.5 min-w-[260px] max-h-[240px] overflow-y-auto custom-scrollbar animate-in fade-in zoom-in-95 duration-100",
12983
+ ref: listRef,
12984
+ onMouseDown: (e) => e.preventDefault()
12985
+ },
12986
+ filtered.length === 0 ? /* @__PURE__ */ import_react27.default.createElement("div", { className: "px-4 py-3 text-xs text-slate-500" }, "Nenhum resultado para", " ", /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-slate-300 font-medium" }, '"', query, '"')) : filtered.map((item, idx) => {
12987
+ const config = TYPE_CONFIG[item.type] || TYPE_CONFIG.node;
12988
+ const { Icon } = config;
12989
+ return /* @__PURE__ */ import_react27.default.createElement(
12990
+ "div",
12991
+ {
12992
+ key: item.id,
12993
+ onMouseDown: (e) => {
12994
+ e.preventDefault();
12995
+ onSelect(item);
12996
+ },
12997
+ onMouseEnter: () => setActiveIndex(idx),
12998
+ className: `flex items-center gap-2.5 px-3 py-2 cursor-pointer text-sm transition-colors duration-100 ${idx === activeIndex ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5"}`
12999
+ },
13000
+ /* @__PURE__ */ import_react27.default.createElement(Icon, { size: 13, className: config.color }),
13001
+ /* @__PURE__ */ import_react27.default.createElement("span", { className: "flex-1 truncate font-medium" }, item.searchLabel || "Sem Nome"),
13002
+ /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[9px] px-1.5 py-0.5 rounded-full bg-white/5 text-slate-500 border border-white/5 uppercase tracking-wide shrink-0" }, config.label)
13003
+ );
13004
+ })
13005
+ );
13006
+ }
12994
13007
 
12995
- // src/components/MentionEditor.jsx
12996
- var CustomMention = import_extension_mention.default.extend({
12997
- addAttributes() {
13008
+ // src/components/RichGroupEditor.jsx
13009
+ var MENTION_BASE_STYLE = "display:inline-flex;align-items:center;padding:1px 7px;border-radius:5px;margin:0 2px;font-size:0.78em;font-weight:600;cursor:pointer;white-space:nowrap;vertical-align:middle;user-select:none;line-height:1.6;";
13010
+ var MENTION_TYPE_STYLE = {
13011
+ ancestry: "background:rgba(99,102,241,0.18);color:#a5b4fc;border:1px solid rgba(99,102,241,0.35);",
13012
+ quest: "background:rgba(16,185,129,0.18);color:#6ee7b7;border:1px solid rgba(16,185,129,0.35);",
13013
+ version: "background:rgba(245,158,11,0.18);color:#fcd34d;border:1px solid rgba(245,158,11,0.35);",
13014
+ node: "background:rgba(100,116,139,0.18);color:#94a3b8;border:1px solid rgba(100,116,139,0.35);"
13015
+ };
13016
+ function mentionStyle(type) {
13017
+ return MENTION_BASE_STYLE + (MENTION_TYPE_STYLE[type] || MENTION_TYPE_STYLE.node);
13018
+ }
13019
+ function escapeHtml(str) {
13020
+ return String(str || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13021
+ }
13022
+ function contentToHTML(content) {
13023
+ if (!content || content.length === 0) return "";
13024
+ return content.map((seg) => {
13025
+ if (seg.type === "text") {
13026
+ return escapeHtml(seg.value).replace(/\n/g, "<br>");
13027
+ }
13028
+ if (seg.type === "mention") {
13029
+ const style = mentionStyle(seg.mentionType);
13030
+ return `<span contenteditable="false" data-mention="true" data-id="${escapeHtml(String(seg.id))}" data-name="${escapeHtml(seg.name || "")}" data-mention-type="${escapeHtml(seg.mentionType || "node")}" style="${style}" title="Clique para focar na cena">@${escapeHtml(seg.name || "")}</span>`;
13031
+ }
13032
+ return "";
13033
+ }).join("");
13034
+ }
13035
+ function domToContent(el) {
13036
+ const segments = [];
13037
+ function pushText(text) {
13038
+ const clean = text.replace(/\u200B/g, "");
13039
+ if (!clean) return;
13040
+ const last = segments[segments.length - 1];
13041
+ if (last && last.type === "text") {
13042
+ last.value += clean;
13043
+ } else {
13044
+ segments.push({ type: "text", value: clean });
13045
+ }
13046
+ }
13047
+ function walk(node) {
12998
13048
  var _a;
12999
- return {
13000
- ...(_a = this.parent) == null ? void 0 : _a.call(this),
13001
- type: {
13002
- default: null,
13003
- parseHTML: (element) => element.getAttribute("data-mention-type"),
13004
- renderHTML: (attributes) => {
13005
- if (!attributes.type) {
13006
- return {};
13007
- }
13008
- return {
13009
- "data-mention-type": attributes.type
13010
- };
13011
- }
13012
- },
13013
- label: {
13014
- default: null,
13015
- parseHTML: (element) => element.getAttribute("data-label"),
13016
- renderHTML: (attributes) => {
13017
- if (!attributes.label) {
13018
- return {};
13019
- }
13020
- return {
13021
- "data-label": attributes.label
13022
- };
13049
+ if (node.nodeType === Node.TEXT_NODE) {
13050
+ pushText(node.textContent);
13051
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
13052
+ if (((_a = node.dataset) == null ? void 0 : _a.mention) === "true") {
13053
+ segments.push({
13054
+ type: "mention",
13055
+ id: node.dataset.id,
13056
+ name: node.dataset.name,
13057
+ mentionType: node.dataset.mentionType
13058
+ });
13059
+ } else if (node.tagName === "BR") {
13060
+ pushText("\n");
13061
+ } else {
13062
+ if (["DIV", "P"].includes(node.tagName) && segments.length > 0) {
13063
+ pushText("\n");
13023
13064
  }
13065
+ node.childNodes.forEach(walk);
13024
13066
  }
13025
- };
13067
+ }
13026
13068
  }
13027
- });
13028
- var MentionEditor = ({
13029
- initialValue = "",
13069
+ el.childNodes.forEach(walk);
13070
+ return segments;
13071
+ }
13072
+ function RichGroupEditor({
13073
+ content,
13030
13074
  onChange,
13031
- onPlay,
13032
- availableItems = [],
13033
- canEdit = true,
13034
- placeholder = "Escreva algo... use @ para mencionar"
13035
- }) => {
13036
- const parseInitialContent = (text) => {
13037
- if (!text) return "<p></p>";
13038
- const parts = text.split(/(\[\[MENTION:[^\]]+\]\])/g);
13039
- return parts.map((part) => {
13040
- const match = part.match(/\[\[MENTION:([^:]+):([^:]+):([^\]]+)\]\]/);
13041
- if (match) {
13042
- const [, type, id, label] = match;
13043
- return `<span data-type="mention" data-id="${id}" data-mention-type="${type}" data-label="${label}">@${label}</span>`;
13044
- }
13045
- return part;
13046
- }).join("");
13047
- };
13048
- const content = (0, import_react28.useMemo)(() => parseInitialContent(initialValue), [initialValue]);
13049
- const editor = (0, import_react29.useEditor)({
13050
- extensions: [
13051
- import_starter_kit.default.configure({
13052
- heading: false,
13053
- bulletList: false,
13054
- orderedList: false,
13055
- codeBlock: false,
13056
- blockquote: false
13057
- }),
13058
- CustomMention.configure({
13059
- HTMLAttributes: {
13060
- class: "mention"
13061
- },
13062
- suggestion: {
13063
- items: ({ query }) => {
13064
- return availableItems.filter(
13065
- (item) => item.name.toLowerCase().includes(query.toLowerCase())
13066
- ).slice(0, 10);
13067
- },
13068
- render: () => {
13069
- let component;
13070
- let popup;
13071
- return {
13072
- onStart: (props) => {
13073
- component = new import_react29.ReactRenderer(MentionList_default, {
13074
- props,
13075
- editor: props.editor
13076
- });
13077
- if (!props.clientRect) {
13078
- return;
13079
- }
13080
- popup = (0, import_tippy.default)("body", {
13081
- getReferenceClientRect: props.clientRect,
13082
- appendTo: () => document.body,
13083
- content: component.element,
13084
- showOnCreate: true,
13085
- interactive: true,
13086
- trigger: "manual",
13087
- placement: "bottom-start",
13088
- theme: "x-view-dark"
13089
- });
13090
- },
13091
- onUpdate(props) {
13092
- component.updateProps(props);
13093
- if (!props.clientRect) {
13094
- return;
13095
- }
13096
- popup[0].setProps({
13097
- getReferenceClientRect: props.clientRect
13098
- });
13099
- },
13100
- onKeyDown(props) {
13101
- var _a;
13102
- if (props.event.key === "Escape") {
13103
- popup[0].hide();
13104
- return true;
13105
- }
13106
- return (_a = component == null ? void 0 : component.ref) == null ? void 0 : _a.onKeyDown(props);
13107
- },
13108
- onExit() {
13109
- if (popup && popup[0]) popup[0].destroy();
13110
- if (component) component.destroy();
13111
- }
13112
- };
13113
- }
13114
- }
13115
- })
13116
- ],
13117
- content,
13118
- editable: canEdit,
13119
- onUpdate: ({ editor: editor2 }) => {
13120
- const serialize = (json) => {
13121
- if (!json.content) return "";
13122
- return json.content.map((block) => {
13123
- if (block.type === "paragraph") {
13124
- const inner = block.content ? block.content.map((node) => {
13125
- if (node.type === "text") return node.text;
13126
- if (node.type === "mention") {
13127
- return `[[MENTION:${node.attrs.type}:${node.attrs.id}:${node.attrs.label}]]`;
13128
- }
13129
- return "";
13130
- }).join("") : "";
13131
- return inner;
13132
- }
13133
- return "";
13134
- }).join("\n").trim();
13135
- };
13136
- const serialized = serialize(editor2.getJSON());
13137
- onChange(serialized);
13075
+ onMentionClick,
13076
+ searchItems,
13077
+ readOnly,
13078
+ placeholder
13079
+ }) {
13080
+ const editorRef = (0, import_react28.useRef)(null);
13081
+ const isMountedRef = (0, import_react28.useRef)(false);
13082
+ const dismissedTriggerRef = (0, import_react28.useRef)(null);
13083
+ const [mentionState, setMentionState] = (0, import_react28.useState)(null);
13084
+ const [isEmpty, setIsEmpty] = (0, import_react28.useState)(true);
13085
+ (0, import_react28.useEffect)(() => {
13086
+ if (!isMountedRef.current && editorRef.current) {
13087
+ editorRef.current.innerHTML = contentToHTML(content);
13088
+ const hasContent = !!editorRef.current.innerText.replace(/\u200B/g, "").trim();
13089
+ const hasMentions = !!editorRef.current.querySelector("[data-mention]");
13090
+ setIsEmpty(!hasContent && !hasMentions);
13091
+ isMountedRef.current = true;
13138
13092
  }
13139
- });
13140
- if (!editor) {
13141
- return null;
13142
- }
13143
- return /* @__PURE__ */ import_react28.default.createElement("div", { className: "relative group/editor min-h-[1.5rem] w-full" }, /* @__PURE__ */ import_react28.default.createElement(
13144
- import_react29.EditorContent,
13145
- {
13146
- editor,
13147
- className: "text-sm text-slate-200 placeholder-slate-600 focus:outline-none"
13148
- }
13149
- ), /* @__PURE__ */ import_react28.default.createElement("style", null, `
13150
- .tiptap p {
13151
- margin: 0;
13152
- min-height: 1.25rem;
13153
- line-height: 1.5;
13154
- }
13155
- .tiptap .mention {
13156
- display: inline-flex;
13157
- align-items: center;
13158
- background: rgba(99, 102, 241, 0.12);
13159
- border: 1px solid rgba(99, 102, 241, 0.25);
13160
- border-radius: 6px;
13161
- padding: 1px 6px;
13162
- color: #a5b4fc;
13163
- font-weight: 600;
13164
- cursor: pointer;
13165
- margin: 0 1px;
13166
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
13167
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
13168
- font-size: 0.85rem;
13169
- text-decoration: none;
13170
- vertical-align: baseline;
13171
- }
13172
- .tiptap .mention:hover {
13173
- background: rgba(99, 102, 241, 0.22);
13174
- border-color: rgba(99, 102, 241, 0.5);
13175
- color: #fff;
13176
- transform: translateY(-1px);
13177
- box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
13178
- }
13179
- .tiptap .mention::before {
13180
- content: "";
13181
- display: inline-block;
13182
- width: 12px;
13183
- height: 12px;
13184
- margin-right: 4px;
13185
- background-size: contain;
13186
- background-repeat: no-repeat;
13187
- opacity: 0.8;
13188
- filter: brightness(1.2);
13189
- }
13190
-
13191
- /* Type specific styles */
13192
- .tiptap .mention[data-mention-type="ancestry"] {
13193
- background: rgba(139, 92, 246, 0.15);
13194
- border-color: rgba(139, 92, 246, 0.3);
13195
- color: #c4b5fd;
13196
- }
13197
- .tiptap .mention[data-mention-type="quest"] {
13198
- background: rgba(16, 185, 129, 0.15);
13199
- border-color: rgba(16, 185, 129, 0.3);
13200
- color: #6ee7b7;
13201
- }
13202
- .tiptap .mention[data-mention-type="node"] {
13203
- background: rgba(59, 130, 246, 0.15);
13204
- border-color: rgba(59, 130, 246, 0.3);
13205
- color: #93c5fd;
13093
+ }, []);
13094
+ const getMentionContext = (0, import_react28.useCallback)(() => {
13095
+ const selection = window.getSelection();
13096
+ if (!selection || selection.rangeCount === 0) return null;
13097
+ const range = selection.getRangeAt(0);
13098
+ const node = range.startContainer;
13099
+ if (node.nodeType !== Node.TEXT_NODE) return null;
13100
+ const textBefore = node.textContent.substring(0, range.startOffset);
13101
+ const atIndex = textBefore.lastIndexOf("@");
13102
+ if (atIndex === -1) {
13103
+ dismissedTriggerRef.current = null;
13104
+ return null;
13105
+ }
13106
+ const charBeforeAt = atIndex > 0 ? textBefore[atIndex - 1] : null;
13107
+ if (charBeforeAt && !/\s/.test(charBeforeAt)) {
13108
+ return null;
13109
+ }
13110
+ if (dismissedTriggerRef.current && dismissedTriggerRef.current.node === node && dismissedTriggerRef.current.atIndex === atIndex) {
13111
+ return null;
13112
+ }
13113
+ const query = textBefore.substring(atIndex + 1);
13114
+ if (query.includes(" ") || query.includes(".") || query.includes(",") || query.length > 40) {
13115
+ return null;
13116
+ }
13117
+ const rect = range.getBoundingClientRect();
13118
+ return {
13119
+ query,
13120
+ position: { top: rect.bottom + 6, left: rect.left }
13121
+ };
13122
+ }, []);
13123
+ const handleInput = (0, import_react28.useCallback)(() => {
13124
+ if (!editorRef.current) return;
13125
+ const serialized = domToContent(editorRef.current);
13126
+ onChange(serialized);
13127
+ const text = editorRef.current.innerText.replace(/\u200B/g, "").trim();
13128
+ const hasMentions = !!editorRef.current.querySelector("[data-mention]");
13129
+ setIsEmpty(!text && !hasMentions);
13130
+ const ctx = getMentionContext();
13131
+ setMentionState(ctx);
13132
+ }, [onChange, getMentionContext]);
13133
+ const handleKeyDown = (0, import_react28.useCallback)(
13134
+ (e) => {
13135
+ if (mentionState && ["ArrowDown", "ArrowUp", "Enter", "Tab", "Escape"].includes(e.key)) {
13136
+ return;
13137
+ }
13138
+ if (e.key === "Enter") {
13139
+ e.preventDefault();
13140
+ const sel = window.getSelection();
13141
+ const range = sel.getRangeAt(0);
13142
+ const br = document.createElement("br");
13143
+ range.deleteContents();
13144
+ range.insertNode(br);
13145
+ const afterBr = br.nextSibling || (() => {
13146
+ const zws = document.createTextNode("\u200B");
13147
+ br.parentNode.insertBefore(zws, br.nextSibling);
13148
+ return zws;
13149
+ })();
13150
+ const newRange = document.createRange();
13151
+ newRange.setStartBefore(afterBr);
13152
+ newRange.collapse(true);
13153
+ sel.removeAllRanges();
13154
+ sel.addRange(newRange);
13155
+ handleInput();
13156
+ }
13157
+ },
13158
+ [mentionState, handleInput]
13159
+ );
13160
+ const insertMention = (0, import_react28.useCallback)(
13161
+ (item) => {
13162
+ if (!editorRef.current) return;
13163
+ const sel = window.getSelection();
13164
+ if (!sel || sel.rangeCount === 0) return;
13165
+ const range = sel.getRangeAt(0);
13166
+ const textNode = range.startContainer;
13167
+ if (textNode.nodeType !== Node.TEXT_NODE) {
13168
+ setMentionState(null);
13169
+ return;
13170
+ }
13171
+ const cursorPos = range.startOffset;
13172
+ const textContent = textNode.textContent;
13173
+ const atIndex = textContent.lastIndexOf("@", cursorPos - 1);
13174
+ if (atIndex === -1) {
13175
+ setMentionState(null);
13176
+ return;
13177
+ }
13178
+ const before = textContent.substring(0, atIndex);
13179
+ const after = textContent.substring(cursorPos);
13180
+ textNode.textContent = before;
13181
+ const parent = textNode.parentNode;
13182
+ const nextSib = textNode.nextSibling;
13183
+ const span = document.createElement("span");
13184
+ span.contentEditable = "false";
13185
+ span.dataset.mention = "true";
13186
+ span.dataset.id = item.id;
13187
+ span.dataset.name = item.searchLabel || item.name || "";
13188
+ span.dataset.mentionType = item.type;
13189
+ span.style.cssText = mentionStyle(item.type);
13190
+ span.title = "Clique para focar na cena";
13191
+ span.textContent = `@${item.searchLabel || item.name || ""}`;
13192
+ parent.insertBefore(span, nextSib);
13193
+ const trailing = document.createTextNode(after || "\u200B");
13194
+ parent.insertBefore(trailing, span.nextSibling);
13195
+ const newRange = document.createRange();
13196
+ newRange.setStart(trailing, after ? 0 : 1);
13197
+ newRange.collapse(true);
13198
+ sel.removeAllRanges();
13199
+ sel.addRange(newRange);
13200
+ const serialized = domToContent(editorRef.current);
13201
+ onChange(serialized);
13202
+ setMentionState(null);
13203
+ setIsEmpty(false);
13204
+ },
13205
+ [onChange]
13206
+ );
13207
+ const handlePaste = (0, import_react28.useCallback)(
13208
+ (e) => {
13209
+ e.preventDefault();
13210
+ const text = e.clipboardData.getData("text/plain");
13211
+ if (text) {
13212
+ document.execCommand("insertText", false, text);
13213
+ handleInput();
13214
+ }
13215
+ },
13216
+ [handleInput]
13217
+ );
13218
+ const handleClick = (0, import_react28.useCallback)(
13219
+ (e) => {
13220
+ const chip = e.target.closest("[data-mention='true']");
13221
+ if (chip && onMentionClick) {
13222
+ e.stopPropagation();
13223
+ const id = chip.dataset.id;
13224
+ const full = searchItems == null ? void 0 : searchItems.find((i) => String(i.id) === String(id));
13225
+ if (full) {
13226
+ onMentionClick(full);
13227
+ } else {
13228
+ onMentionClick({
13229
+ id,
13230
+ name: chip.dataset.name,
13231
+ type: chip.dataset.mentionType,
13232
+ searchLabel: chip.dataset.name
13233
+ });
13206
13234
  }
13207
- .tiptap .mention[data-mention-type="version"] {
13208
- background: rgba(245, 158, 11, 0.15);
13209
- border-color: rgba(245, 158, 11, 0.3);
13210
- color: #fcd34d;
13235
+ return;
13236
+ }
13237
+ },
13238
+ [onMentionClick, getMentionContext, searchItems]
13239
+ );
13240
+ const handleBlur = (0, import_react28.useCallback)(() => {
13241
+ setTimeout(() => setMentionState(null), 200);
13242
+ }, []);
13243
+ const handleMentionDismiss = (0, import_react28.useCallback)(() => {
13244
+ const selection = window.getSelection();
13245
+ if (selection && selection.rangeCount > 0) {
13246
+ const range = selection.getRangeAt(0);
13247
+ const node = range.startContainer;
13248
+ if (node.nodeType === Node.TEXT_NODE) {
13249
+ const textBefore = node.textContent.substring(0, range.startOffset);
13250
+ const atIndex = textBefore.lastIndexOf("@");
13251
+ if (atIndex !== -1) {
13252
+ dismissedTriggerRef.current = { node, atIndex };
13211
13253
  }
13254
+ }
13255
+ }
13256
+ setMentionState(null);
13257
+ }, []);
13258
+ return /* @__PURE__ */ import_react28.default.createElement("div", { className: "relative" }, isEmpty && !readOnly && /* @__PURE__ */ import_react28.default.createElement("div", { className: "absolute top-0 left-0 text-sm text-slate-600 pointer-events-none select-none" }, placeholder || "Escreva sobre este grupo\u2026 ou digite @ para mencionar"), /* @__PURE__ */ import_react28.default.createElement(
13259
+ "div",
13260
+ {
13261
+ ref: editorRef,
13262
+ contentEditable: readOnly ? "false" : "true",
13263
+ suppressContentEditableWarning: true,
13264
+ onInput: handleInput,
13265
+ onKeyDown: handleKeyDown,
13266
+ onPaste: handlePaste,
13267
+ onClick: handleClick,
13268
+ onBlur: handleBlur,
13269
+ className: `w-full min-h-[1.5rem] max-h-[250px] overflow-y-auto text-sm text-slate-200 focus:outline-none leading-relaxed ${!readOnly ? "cursor-text" : "cursor-default"}`,
13270
+ style: { overflowWrap: "break-word", wordBreak: "break-word" }
13271
+ }
13272
+ ), mentionState && !readOnly && /* @__PURE__ */ import_react28.default.createElement(
13273
+ MentionPopover,
13274
+ {
13275
+ query: mentionState.query,
13276
+ items: searchItems || [],
13277
+ position: mentionState.position,
13278
+ onSelect: insertMention,
13279
+ onClose: handleMentionDismiss
13280
+ }
13281
+ ));
13282
+ }
13212
13283
 
13213
- .tiptap:focus {
13214
- outline: none;
13215
- }
13216
-
13217
- .ProseMirror-placeholder:first-child::before {
13218
- content: attr(data-placeholder);
13219
- float: left;
13220
- color: #475569;
13221
- pointer-events: none;
13222
- height: 0;
13223
- font-style: italic;
13224
- }
13225
- `));
13284
+ // src/components/Boards.jsx
13285
+ var Tooltip = ({ text, children }) => {
13286
+ if (!text) return children;
13287
+ return /* @__PURE__ */ import_react29.default.createElement("div", { className: "relative group/tooltip" }, children, /* @__PURE__ */ import_react29.default.createElement("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-slate-900 border border-white/10 text-white text-[10px] rounded opacity-0 group-hover/tooltip:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-[3000] shadow-2xl" }, text));
13226
13288
  };
13227
- var MentionEditor_default = MentionEditor;
13228
-
13229
- // src/components/AncestryBoard.jsx
13230
- var GroupItem = ({
13231
- group,
13289
+ var BoardItem = ({
13290
+ item,
13232
13291
  index,
13292
+ prevItem,
13293
+ nextItem,
13233
13294
  onUpdate,
13234
13295
  onDelete,
13235
13296
  onAddSubgroup,
13236
13297
  onIndent,
13298
+ onIndentDown,
13237
13299
  onOutdent,
13238
- onPlayAncestry,
13239
- availableMentionItems,
13240
- canEdit
13300
+ onMoveUp,
13301
+ onMoveDown,
13302
+ searchItems,
13303
+ onMentionClick,
13304
+ onEnterFolder,
13305
+ canEdit,
13306
+ isAtRoot = false
13241
13307
  }) => {
13242
- const canIndent = index > 0;
13243
- return /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react30.default.createElement(
13244
- "div",
13245
- {
13246
- className: "flex flex-col gap-2 py-2 px-3 transition-all duration-200 hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"
13247
- },
13248
- /* @__PURE__ */ import_react30.default.createElement(
13249
- MentionEditor_default,
13250
- {
13251
- initialValue: group.text,
13252
- onChange: (newText) => {
13253
- if (canEdit) onUpdate(group.id, { ...group, text: newText });
13254
- },
13255
- onPlay: onPlayAncestry,
13256
- availableItems: availableMentionItems,
13257
- canEdit,
13258
- placeholder: "Escreva sobre este grupo... use @ para mencionar"
13259
- }
13260
- ),
13261
- canEdit && /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-0 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react30.default.createElement(
13262
- "button",
13263
- {
13264
- onClick: () => onAddSubgroup(group.id),
13265
- className: "flex items-center gap-1.5 px-3 py-1.5 text-xs text-slate-500 hover:text-white hover:bg-white/10 rounded-md transition-colors",
13266
- title: "Criar Subgrupo"
13267
- },
13268
- /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiPlus, { size: 14 }),
13269
- /* @__PURE__ */ import_react30.default.createElement("span", null, "Adicionar Subgrupo")
13270
- )), /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react30.default.createElement(
13271
- "button",
13272
- {
13273
- onClick: () => onIndent(group.id),
13274
- disabled: !canIndent,
13275
- className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
13276
- title: "Aninhar no grupo acima"
13277
- },
13278
- /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiArrowRight, { size: 14 })
13279
- ), /* @__PURE__ */ import_react30.default.createElement(
13280
- "button",
13281
- {
13282
- onClick: () => onOutdent(group.id),
13283
- className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13284
- title: "Desaninhar"
13285
- },
13286
- /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiArrowLeft, { size: 14 })
13287
- ), /* @__PURE__ */ import_react30.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react30.default.createElement(
13288
- "button",
13308
+ var _a;
13309
+ const isFolder = item.type === "folder";
13310
+ const canMoveUp = index > 0;
13311
+ const canMoveDown = nextItem !== void 0;
13312
+ const isNested = onOutdent !== void 0;
13313
+ const getIndentUpTooltip = () => {
13314
+ if (!prevItem) return null;
13315
+ const typeLabel = prevItem.type === "folder" ? "pasta" : "grupo de texto";
13316
+ return isFolder ? prevItem.type === "folder" ? "Aninhar na pasta acima" : null : `Mover para dentro do ${typeLabel} acima`;
13317
+ };
13318
+ const getIndentDownTooltip = () => {
13319
+ if (!nextItem) return null;
13320
+ const typeLabel = nextItem.type === "folder" ? "pasta" : "grupo de texto";
13321
+ return isFolder ? nextItem.type === "folder" ? "Aninhar na pasta abaixo" : null : `Mover para dentro do ${typeLabel} abaixo`;
13322
+ };
13323
+ const showIndentUp = !!getIndentUpTooltip();
13324
+ const showIndentDown = !!getIndentDownTooltip();
13325
+ const handleContentChange = (content) => {
13326
+ onUpdate(item.id, { ...item, content });
13327
+ };
13328
+ const handleNameChange = (e) => {
13329
+ onUpdate(item.id, { ...item, name: e.target.value });
13330
+ };
13331
+ if (isFolder) {
13332
+ return /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col gap-2 mb-3 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react29.default.createElement(
13333
+ "div",
13289
13334
  {
13290
- onClick: () => onDelete(group.id),
13291
- className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
13292
- title: "Remover Grupo"
13335
+ onClick: () => onEnterFolder(item.id),
13336
+ className: "flex items-center gap-3 py-3 px-4 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 rounded-xl cursor-pointer transition-all duration-200 group/folder"
13293
13337
  },
13294
- /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiTrash2, { size: 14 })
13295
- )))
13296
- ), group.children && group.children.length > 0 && /* @__PURE__ */ import_react30.default.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ import_react30.default.createElement(
13297
- GroupItem,
13298
- {
13299
- key: childGroup.id,
13300
- index: idx,
13301
- group: childGroup,
13302
- siblings: group.children,
13303
- onUpdate,
13304
- onDelete,
13305
- onAddSubgroup,
13306
- onIndent,
13307
- onOutdent,
13308
- onPlayAncestry,
13309
- availableMentionItems,
13310
- canEdit
13311
- }
13312
- ))));
13313
- };
13314
- function AncestryBoard({
13315
- isOpen,
13316
- onClose,
13317
- onSelect,
13318
- availableAncestries = [],
13319
- availableNodes = [],
13320
- initialGroups = [],
13321
- onSave,
13322
- userRole
13323
- }) {
13324
- const [groups, setGroups] = (0, import_react30.useState)([]);
13325
- const [isLoaded, setIsLoaded] = (0, import_react30.useState)(false);
13326
- const [saveStatus, setSaveStatus] = (0, import_react30.useState)("idle");
13327
- const canEdit = (0, import_react30.useMemo)(() => {
13328
- return userRole !== "viewer";
13329
- }, [userRole]);
13330
- (0, import_react30.useEffect)(() => {
13331
- if (initialGroups && !isLoaded) {
13332
- setGroups(initialGroups);
13333
- setIsLoaded(true);
13334
- }
13335
- }, [initialGroups, isLoaded]);
13336
- const nodeNamesMap = (0, import_react30.useMemo)(() => {
13337
- const map = /* @__PURE__ */ new Map();
13338
- if (availableNodes && Array.isArray(availableNodes)) {
13339
- availableNodes.forEach((node) => {
13340
- if (node && node.id) {
13341
- map.set(String(node.id), node.name);
13338
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-10 h-10 rounded-lg bg-indigo-500/10 flex items-center justify-center text-indigo-400 group-hover/folder:scale-110 transition-transform" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiFolder, { size: 20 })),
13339
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex-1 min-w-0" }, canEdit ? /* @__PURE__ */ import_react29.default.createElement(
13340
+ "input",
13341
+ {
13342
+ type: "text",
13343
+ value: item.name,
13344
+ onChange: handleNameChange,
13345
+ onClick: (e) => e.stopPropagation(),
13346
+ className: "bg-transparent border-none outline-none text-sm font-medium text-slate-200 w-full focus:text-white",
13347
+ placeholder: "Nome da pasta..."
13342
13348
  }
13343
- });
13344
- }
13345
- return map;
13346
- }, [availableNodes]);
13347
- const availableIds = (0, import_react30.useMemo)(() => {
13348
- return new Set(availableAncestries.map((a) => String(a.ancestry_id)));
13349
- }, [availableAncestries]);
13350
- const availableMentionItems = (0, import_react30.useMemo)(() => {
13351
- const ancestries = availableAncestries.map((a) => ({
13352
- id: String(a.ancestry_id),
13353
- ancestry_id: a.ancestry_id,
13354
- name: a.name,
13355
- description: a.description,
13356
- type: "ancestry",
13357
- ancestral_node: a.ancestral_node,
13358
- is_private: a.is_private
13359
- }));
13360
- const nodes = availableNodes.map((n) => {
13361
- let type = "node";
13362
- if (n.is_quest) type = "quest";
13363
- else if (n.is_version) type = "version";
13364
- return {
13365
- id: String(n.id),
13366
- name: n.name,
13367
- description: n.description,
13368
- type,
13369
- raw_node: n
13370
- };
13371
- });
13372
- return [...ancestries, ...nodes];
13373
- }, [availableAncestries, availableNodes]);
13374
- const sanitizeGroups = (groupList) => {
13375
- return groupList.map((g) => ({
13376
- id: g.id,
13377
- text: g.text || "",
13378
- children: sanitizeGroups(g.children || [])
13379
- }));
13380
- };
13381
- (0, import_react30.useEffect)(() => {
13382
- if (!isLoaded || !onSave) return;
13383
- const timeoutId = setTimeout(async () => {
13384
- setSaveStatus("saving");
13385
- const cleanData = sanitizeGroups(groups);
13386
- try {
13387
- await onSave(cleanData);
13388
- setSaveStatus("saved");
13389
- setTimeout(() => {
13390
- setSaveStatus("idle");
13391
- }, 3e3);
13392
- } catch (error) {
13393
- console.error("Erro ao salvar board:", error);
13394
- setSaveStatus("error");
13395
- }
13396
- }, 3e3);
13397
- return () => clearTimeout(timeoutId);
13398
- }, [groups, isLoaded, onSave]);
13399
- (0, import_react30.useEffect)(() => {
13400
- if (!isOpen) return;
13401
- const handleKeyDown = (e) => {
13402
- if (e.key === "Escape") {
13403
- onClose();
13404
- e.preventDefault();
13405
- e.stopPropagation();
13406
- }
13407
- };
13408
- window.addEventListener("keydown", handleKeyDown);
13409
- return () => window.removeEventListener("keydown", handleKeyDown);
13410
- }, [isOpen, onClose]);
13411
- const handleAddRootGroup = () => {
13412
- const newGroup = {
13413
- id: (0, import_uuid11.v4)(),
13414
- text: "",
13415
- children: []
13349
+ ) : /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-sm font-medium text-slate-200" }, item.name), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-2 mt-0.5" }, /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider font-semibold" }, ((_a = item.children) == null ? void 0 : _a.length) || 0, " itens"))),
13350
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1.5 opacity-0 group-item/item:opacity-100 group-hover/folder:opacity-100 transition-opacity" }, canEdit && /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-0.5 bg-slate-900/80 backdrop-blur-sm p-1 rounded-lg border border-white/5 shadow-xl" }, /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Subir" }, /* @__PURE__ */ import_react29.default.createElement(
13351
+ "button",
13352
+ {
13353
+ onClick: (e) => {
13354
+ e.stopPropagation();
13355
+ onMoveUp(item.id);
13356
+ },
13357
+ disabled: !canMoveUp,
13358
+ className: `p-1.5 rounded transition-colors ${!canMoveUp ? "text-slate-800 cursor-not-allowed" : "text-slate-400 hover:text-white hover:bg-white/10"}`
13359
+ },
13360
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowUp, { size: 14 })
13361
+ )), /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Descer" }, /* @__PURE__ */ import_react29.default.createElement(
13362
+ "button",
13363
+ {
13364
+ onClick: (e) => {
13365
+ e.stopPropagation();
13366
+ onMoveDown(item.id);
13367
+ },
13368
+ disabled: !canMoveDown,
13369
+ className: `p-1.5 rounded transition-colors ${!canMoveDown ? "text-slate-800 cursor-not-allowed" : "text-slate-400 hover:text-white hover:bg-white/10"}`
13370
+ },
13371
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowDown, { size: 14 })
13372
+ )), /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-0.5" }), showIndentUp && /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: getIndentUpTooltip() }, /* @__PURE__ */ import_react29.default.createElement(
13373
+ "button",
13374
+ {
13375
+ onClick: (e) => {
13376
+ e.stopPropagation();
13377
+ onIndent(item.id);
13378
+ },
13379
+ className: "p-1.5 text-slate-400 hover:text-white hover:bg-white/10 rounded transition-colors"
13380
+ },
13381
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowLeft, { size: 14 })
13382
+ )), showIndentDown && /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: getIndentDownTooltip() }, /* @__PURE__ */ import_react29.default.createElement(
13383
+ "button",
13384
+ {
13385
+ onClick: (e) => {
13386
+ e.stopPropagation();
13387
+ onIndentDown(item.id);
13388
+ },
13389
+ className: "p-1.5 text-slate-400 hover:text-white hover:bg-white/10 rounded transition-colors"
13390
+ },
13391
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowRight, { size: 14 })
13392
+ )), !isAtRoot && /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Desaninhar / Recuar n\xEDvel" }, /* @__PURE__ */ import_react29.default.createElement(
13393
+ "button",
13394
+ {
13395
+ onClick: (e) => {
13396
+ e.stopPropagation();
13397
+ onOutdent(item.id);
13398
+ },
13399
+ disabled: !onOutdent,
13400
+ className: `p-1.5 rounded transition-colors ${!onOutdent ? "text-slate-800 cursor-not-allowed" : "text-slate-400 hover:text-white hover:bg-white/10"}`
13401
+ },
13402
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiCornerUpLeft, { size: 14 })
13403
+ )), /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-0.5" }), /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Remover Pasta" }, /* @__PURE__ */ import_react29.default.createElement(
13404
+ "button",
13405
+ {
13406
+ onClick: (e) => {
13407
+ e.stopPropagation();
13408
+ onDelete(item.id);
13409
+ },
13410
+ className: "p-1.5 text-slate-500 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors"
13411
+ },
13412
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiTrash2, { size: 14 })
13413
+ ))), /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiChevronRight, { className: "text-slate-500 group-hover/folder:translate-x-1 transition-transform" }))
13414
+ ));
13415
+ }
13416
+ return /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col gap-2 py-2 px-3 transition-all duration-200 hover:bg-white/5 border-l-2 border-transparent hover:border-white/20" }, /* @__PURE__ */ import_react29.default.createElement(
13417
+ RichGroupEditor,
13418
+ {
13419
+ content: item.content,
13420
+ onChange: handleContentChange,
13421
+ onMentionClick,
13422
+ searchItems,
13423
+ readOnly: !canEdit,
13424
+ placeholder: "Escreva sobre este grupo de texto\u2026 ou @ para mencionar"
13425
+ }
13426
+ ), canEdit && /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react29.default.createElement(
13427
+ "button",
13428
+ {
13429
+ onClick: () => onAddSubgroup(item.id, "text_group"),
13430
+ className: "flex items-center gap-1 px-1.5 py-1 text-[10px] uppercase font-bold tracking-wider text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13431
+ title: "Criar Subgrupo de Texto"
13432
+ },
13433
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiPlus, { size: 12 }),
13434
+ /* @__PURE__ */ import_react29.default.createElement("span", null, "Subgrupo")
13435
+ )), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Subir" }, /* @__PURE__ */ import_react29.default.createElement(
13436
+ "button",
13437
+ {
13438
+ onClick: () => onMoveUp(item.id),
13439
+ disabled: !canMoveUp,
13440
+ className: `p-1.5 rounded transition-colors ${!canMoveUp ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`
13441
+ },
13442
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowUp, { size: 14 })
13443
+ )), /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Descer" }, /* @__PURE__ */ import_react29.default.createElement(
13444
+ "button",
13445
+ {
13446
+ onClick: () => onMoveDown(item.id),
13447
+ disabled: !canMoveDown,
13448
+ className: `p-1.5 rounded transition-colors ${!canMoveDown ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`
13449
+ },
13450
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowDown, { size: 14 })
13451
+ )), /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), showIndentUp && /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: getIndentUpTooltip() }, /* @__PURE__ */ import_react29.default.createElement(
13452
+ "button",
13453
+ {
13454
+ onClick: () => onIndent(item.id),
13455
+ className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors"
13456
+ },
13457
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowLeft, { size: 14 })
13458
+ )), showIndentDown && /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: getIndentDownTooltip() }, /* @__PURE__ */ import_react29.default.createElement(
13459
+ "button",
13460
+ {
13461
+ onClick: () => onIndentDown(item.id),
13462
+ className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors"
13463
+ },
13464
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowRight, { size: 14 })
13465
+ )), !isAtRoot && /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Desaninhar / Recuar n\xEDvel" }, /* @__PURE__ */ import_react29.default.createElement(
13466
+ "button",
13467
+ {
13468
+ onClick: () => onOutdent(item.id),
13469
+ disabled: !onOutdent,
13470
+ className: `p-1.5 rounded transition-colors ${!onOutdent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`
13471
+ },
13472
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiCornerUpLeft, { size: 14 })
13473
+ )), /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react29.default.createElement(Tooltip, { text: "Remover Grupo de Texto" }, /* @__PURE__ */ import_react29.default.createElement(
13474
+ "button",
13475
+ {
13476
+ onClick: () => onDelete(item.id),
13477
+ className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors"
13478
+ },
13479
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiTrash2, { size: 14 })
13480
+ ))))), item.children && item.children.length > 0 && /* @__PURE__ */ import_react29.default.createElement("div", { className: "ml-2" }, item.children.map((child, idx) => /* @__PURE__ */ import_react29.default.createElement(
13481
+ BoardItem,
13482
+ {
13483
+ key: child.id,
13484
+ index: idx,
13485
+ prevItem: item.children[idx - 1],
13486
+ nextItem: item.children[idx + 1],
13487
+ item: child,
13488
+ onUpdate,
13489
+ onDelete,
13490
+ onAddSubgroup,
13491
+ onIndent,
13492
+ onIndentDown,
13493
+ onOutdent,
13494
+ onMoveUp,
13495
+ onMoveDown,
13496
+ searchItems,
13497
+ onMentionClick,
13498
+ onEnterFolder,
13499
+ canEdit,
13500
+ isAtRoot: false
13501
+ }
13502
+ ))));
13503
+ };
13504
+ function Boards({
13505
+ isOpen,
13506
+ onClose,
13507
+ onSelect,
13508
+ availableAncestries = [],
13509
+ availableNodes = [],
13510
+ initialBoardItems = [],
13511
+ onSave,
13512
+ userRole
13513
+ }) {
13514
+ const [boardItems, setBoardItems] = (0, import_react29.useState)([]);
13515
+ const [isLoaded, setIsLoaded] = (0, import_react29.useState)(false);
13516
+ const [saveStatus, setSaveStatus] = (0, import_react29.useState)("idle");
13517
+ const [navigationStack, setNavigationStack] = (0, import_react29.useState)([]);
13518
+ const lastSavedBoardItemsRef = (0, import_react29.useRef)(null);
13519
+ const canEdit = (0, import_react29.useMemo)(() => userRole !== "viewer", [userRole]);
13520
+ const sanitizeBoardItems = (list) => list.map((g) => ({
13521
+ id: g.id,
13522
+ type: g.type || "text_group",
13523
+ name: g.name || "",
13524
+ content: g.content || [],
13525
+ children: sanitizeBoardItems(g.children || [])
13526
+ }));
13527
+ (0, import_react29.useEffect)(() => {
13528
+ if (initialBoardItems && !isLoaded) {
13529
+ const hasLegacyTypes = (list) => list.some(
13530
+ (g) => g.type === "group" || hasLegacyTypes(g.children || [])
13531
+ );
13532
+ let preparedItems = [];
13533
+ if (hasLegacyTypes(initialBoardItems)) {
13534
+ console.warn("Legacy Boards detected. Resetting board to empty list.");
13535
+ preparedItems = [];
13536
+ } else {
13537
+ const prepare = (list) => list.map((g) => ({
13538
+ id: g.id || (0, import_uuid11.v4)(),
13539
+ type: g.type || "text_group",
13540
+ name: g.name || "",
13541
+ content: Array.isArray(g.content) ? g.content : [],
13542
+ children: prepare(g.children || [])
13543
+ }));
13544
+ preparedItems = prepare(initialBoardItems);
13545
+ }
13546
+ setBoardItems(preparedItems);
13547
+ lastSavedBoardItemsRef.current = JSON.stringify(
13548
+ sanitizeBoardItems(preparedItems)
13549
+ );
13550
+ setIsLoaded(true);
13551
+ }
13552
+ }, [initialBoardItems, isLoaded]);
13553
+ const allSearchableItems = (0, import_react29.useMemo)(() => {
13554
+ const items = [];
13555
+ availableAncestries.forEach((anc) => {
13556
+ items.push({
13557
+ ...anc,
13558
+ id: String(anc.ancestry_id),
13559
+ type: "ancestry",
13560
+ searchLabel: anc.name || "",
13561
+ searchDesc: anc.description || ""
13562
+ });
13563
+ });
13564
+ availableNodes.forEach((node) => {
13565
+ var _a;
13566
+ let type = "node";
13567
+ if (node.is_quest) type = "quest";
13568
+ else if ((_a = node.version_node) == null ? void 0 : _a.is_version) type = "version";
13569
+ items.push({
13570
+ ...node,
13571
+ id: String(node.id),
13572
+ type,
13573
+ searchLabel: node.name || node.raw_title || "",
13574
+ searchDesc: node.description || ""
13575
+ });
13576
+ });
13577
+ return items;
13578
+ }, [availableAncestries, availableNodes]);
13579
+ (0, import_react29.useEffect)(() => {
13580
+ if (!isLoaded || !onSave) return;
13581
+ const id = setTimeout(async () => {
13582
+ const currentSanitized = sanitizeBoardItems(boardItems);
13583
+ const currentJson = JSON.stringify(currentSanitized);
13584
+ if (currentJson === lastSavedBoardItemsRef.current) return;
13585
+ setSaveStatus("saving");
13586
+ try {
13587
+ await onSave(currentSanitized);
13588
+ lastSavedBoardItemsRef.current = currentJson;
13589
+ setSaveStatus("saved");
13590
+ setTimeout(() => setSaveStatus("idle"), 3e3);
13591
+ } catch (err) {
13592
+ console.error("Erro ao salvar board:", err);
13593
+ setSaveStatus("error");
13594
+ }
13595
+ }, 3e3);
13596
+ return () => clearTimeout(id);
13597
+ }, [boardItems, isLoaded, onSave]);
13598
+ const triggerInstantSave = async (updatedBoardItems) => {
13599
+ if (!onSave) return;
13600
+ const sanitized = sanitizeBoardItems(updatedBoardItems);
13601
+ const sanitizedJson = JSON.stringify(sanitized);
13602
+ lastSavedBoardItemsRef.current = sanitizedJson;
13603
+ setSaveStatus("saving");
13604
+ try {
13605
+ await onSave(sanitized);
13606
+ setSaveStatus("saved");
13607
+ setTimeout(() => setSaveStatus("idle"), 3e3);
13608
+ } catch (err) {
13609
+ console.error("Erro ao salvar board:", err);
13610
+ setSaveStatus("error");
13611
+ }
13612
+ };
13613
+ (0, import_react29.useEffect)(() => {
13614
+ if (!isOpen) return;
13615
+ const handler = (e) => {
13616
+ if (e.key === "Escape") {
13617
+ onClose();
13618
+ e.preventDefault();
13619
+ e.stopPropagation();
13620
+ }
13416
13621
  };
13417
- setGroups((prev) => [newGroup, ...prev]);
13622
+ window.addEventListener("keydown", handler);
13623
+ return () => window.removeEventListener("keydown", handler);
13624
+ }, [isOpen, onClose]);
13625
+ const currentPath = (0, import_react29.useMemo)(() => {
13626
+ const path = [];
13627
+ let currentLevel = boardItems;
13628
+ for (const folderId of navigationStack) {
13629
+ const folder = currentLevel.find((f) => f.id === folderId);
13630
+ if (folder) {
13631
+ path.push(folder);
13632
+ currentLevel = folder.children;
13633
+ }
13634
+ }
13635
+ return path;
13636
+ }, [boardItems, navigationStack]);
13637
+ const currentBoardItems = (0, import_react29.useMemo)(() => {
13638
+ const lastFolder = currentPath[currentPath.length - 1];
13639
+ return lastFolder ? lastFolder.children : boardItems;
13640
+ }, [boardItems, currentPath]);
13641
+ const navigateUp = () => {
13642
+ setNavigationStack((prev) => prev.slice(0, -1));
13643
+ };
13644
+ const navigateTo = (folderId) => {
13645
+ setNavigationStack((prev) => [...prev, folderId]);
13646
+ };
13647
+ const navigateToBreadcrumb = (index) => {
13648
+ setNavigationStack((prev) => prev.slice(0, index + 1));
13649
+ };
13650
+ const navigateHome = () => {
13651
+ setNavigationStack([]);
13418
13652
  };
13419
- const handleAddSubgroup = (parentId) => {
13420
- const newGroup = {
13653
+ const handleAddItem = (type = "text_group") => {
13654
+ const newItem = {
13421
13655
  id: (0, import_uuid11.v4)(),
13422
- text: "",
13656
+ type,
13657
+ name: type === "folder" ? "Nova Pasta" : "",
13658
+ content: [],
13423
13659
  children: []
13424
13660
  };
13425
- const addRecursive = (list) => {
13426
- return list.map((g) => {
13427
- if (g.id === parentId) {
13428
- return { ...g, children: [newGroup, ...g.children] };
13429
- }
13430
- return { ...g, children: addRecursive(g.children) };
13431
- });
13432
- };
13433
- setGroups((prev) => addRecursive(prev));
13661
+ if (navigationStack.length === 0) {
13662
+ setBoardItems((prev) => [...prev, newItem]);
13663
+ } else {
13664
+ const parentId = navigationStack[navigationStack.length - 1];
13665
+ const add = (list) => list.map(
13666
+ (g) => g.id === parentId ? { ...g, children: [...g.children, newItem] } : { ...g, children: add(g.children) }
13667
+ );
13668
+ setBoardItems((prev) => add(prev));
13669
+ }
13434
13670
  };
13435
- const handleUpdateGroup = (id, newData) => {
13436
- const updateRecursive = (list) => {
13437
- return list.map((g) => {
13438
- if (g.id === id) return newData;
13439
- return { ...g, children: updateRecursive(g.children) };
13440
- });
13441
- };
13442
- setGroups((prev) => updateRecursive(prev));
13671
+ const handleAddSubgroup = (parentId, type = "text_group") => {
13672
+ const add = (list) => list.map((g) => {
13673
+ if (g.id === parentId) {
13674
+ if (g.type === "text_group" && type === "folder") return g;
13675
+ const newItem = {
13676
+ id: (0, import_uuid11.v4)(),
13677
+ type,
13678
+ name: type === "folder" ? "Nova Pasta" : "",
13679
+ content: [],
13680
+ children: []
13681
+ };
13682
+ return { ...g, children: [...g.children, newItem] };
13683
+ }
13684
+ return { ...g, children: add(g.children) };
13685
+ });
13686
+ setBoardItems((prev) => add(prev));
13443
13687
  };
13444
- const handleDeleteGroup = (id) => {
13445
- const deleteRecursive = (list) => {
13446
- return list.filter((g) => g.id !== id).map((g) => ({
13447
- ...g,
13448
- children: deleteRecursive(g.children)
13449
- }));
13450
- };
13451
- setGroups((prev) => deleteRecursive(prev));
13688
+ const handleUpdateItem = (id, newData) => {
13689
+ const update = (list) => list.map(
13690
+ (g) => g.id === id ? newData : { ...g, children: update(g.children) }
13691
+ );
13692
+ setBoardItems((prev) => update(prev));
13693
+ };
13694
+ const handleDeleteItem = (id) => {
13695
+ const del = (list) => list.filter((g) => g.id !== id).map((g) => ({ ...g, children: del(g.children) }));
13696
+ setBoardItems((prev) => del(prev));
13452
13697
  };
13453
13698
  const findGroupAndParent = (list, targetId, parent = null) => {
13454
13699
  for (let i = 0; i < list.length; i++) {
13455
- if (list[i].id === targetId) {
13700
+ if (list[i].id === targetId)
13456
13701
  return { group: list[i], parent, index: i, siblings: list };
13457
- }
13458
13702
  if (list[i].children.length > 0) {
13459
13703
  const found = findGroupAndParent(list[i].children, targetId, list[i]);
13460
13704
  if (found) return found;
@@ -13463,113 +13707,169 @@ function AncestryBoard({
13463
13707
  return null;
13464
13708
  };
13465
13709
  const handleIndent = (id) => {
13466
- setGroups((prev) => {
13467
- const newList = JSON.parse(JSON.stringify(prev));
13468
- const found = findGroupAndParent(newList, id);
13469
- if (!found || found.index === 0) return prev;
13470
- const { group, siblings, index } = found;
13471
- const prevSibling = siblings[index - 1];
13472
- siblings.splice(index, 1);
13473
- prevSibling.children.push(group);
13474
- return newList;
13475
- });
13710
+ const next = JSON.parse(JSON.stringify(boardItems));
13711
+ const found = findGroupAndParent(next, id);
13712
+ if (!found || found.index === 0) return;
13713
+ const { group, siblings, index } = found;
13714
+ const targetParent = siblings[index - 1];
13715
+ if (group.type === "folder" && targetParent.type === "text_group") {
13716
+ return;
13717
+ }
13718
+ siblings.splice(index, 1);
13719
+ targetParent.children.push(group);
13720
+ setBoardItems(next);
13721
+ triggerInstantSave(next);
13476
13722
  };
13477
- const handleOutdent = (id) => {
13478
- setGroups((prev) => {
13479
- const newList = JSON.parse(JSON.stringify(prev));
13480
- const found = findGroupAndParent(newList, id);
13481
- if (!found || !found.parent) return prev;
13482
- const { group, siblings, index, parent } = found;
13483
- siblings.splice(index, 1);
13484
- const parentFound = findGroupAndParent(newList, parent.id);
13485
- if (parentFound) {
13486
- parentFound.siblings.splice(parentFound.index + 1, 0, group);
13487
- } else {
13488
- newList.push(group);
13489
- }
13490
- return newList;
13491
- });
13723
+ const handleIndentDown = (id) => {
13724
+ const next = JSON.parse(JSON.stringify(boardItems));
13725
+ const found = findGroupAndParent(next, id);
13726
+ if (!found || found.index === found.siblings.length - 1) return;
13727
+ const { group, siblings, index } = found;
13728
+ const targetParent = siblings[index + 1];
13729
+ if (group.type === "folder" && targetParent.type === "text_group") {
13730
+ return;
13731
+ }
13732
+ siblings.splice(index, 1);
13733
+ targetParent.children.push(group);
13734
+ setBoardItems(next);
13735
+ triggerInstantSave(next);
13492
13736
  };
13493
- const handlePlayFromGroup = (item) => {
13494
- let fullItem = item;
13495
- if (item.type === "ancestry" || !item.type) {
13496
- fullItem = availableAncestries.find(
13497
- (a) => String(a.ancestry_id) === String(item.id || item.ancestry_id)
13498
- ) || item;
13737
+ const handleOutdent = (id) => {
13738
+ const next = JSON.parse(JSON.stringify(boardItems));
13739
+ const found = findGroupAndParent(next, id);
13740
+ if (!found || !found.parent) return;
13741
+ const { group, siblings, index, parent } = found;
13742
+ siblings.splice(index, 1);
13743
+ const parentFound = findGroupAndParent(next, parent.id);
13744
+ if (parentFound) {
13745
+ parentFound.siblings.splice(parentFound.index + 1, 0, group);
13499
13746
  } else {
13500
- fullItem = availableNodes.find(
13501
- (n) => String(n.id) === String(item.id)
13502
- ) || item;
13503
- }
13504
- if (fullItem && onSelect) {
13505
- onSelect(fullItem);
13747
+ next.push(group);
13506
13748
  }
13749
+ setBoardItems(next);
13750
+ triggerInstantSave(next);
13751
+ };
13752
+ const handleMoveUp = (id) => {
13753
+ const next = JSON.parse(JSON.stringify(boardItems));
13754
+ const found = findGroupAndParent(next, id);
13755
+ if (!found || found.index === 0) return;
13756
+ const { siblings, index } = found;
13757
+ const item = siblings[index];
13758
+ siblings.splice(index, 1);
13759
+ siblings.splice(index - 1, 0, item);
13760
+ setBoardItems(next);
13761
+ triggerInstantSave(next);
13762
+ };
13763
+ const handleMoveDown = (id) => {
13764
+ const next = JSON.parse(JSON.stringify(boardItems));
13765
+ const found = findGroupAndParent(next, id);
13766
+ if (!found || found.index === found.siblings.length - 1) return;
13767
+ const { siblings, index } = found;
13768
+ const item = siblings[index];
13769
+ siblings.splice(index, 1);
13770
+ siblings.splice(index + 1, 0, item);
13771
+ setBoardItems(next);
13772
+ triggerInstantSave(next);
13773
+ };
13774
+ const handleMentionClick = (item) => {
13775
+ if (onSelect) onSelect(item);
13507
13776
  };
13508
13777
  if (!isOpen) return null;
13509
- return /* @__PURE__ */ import_react30.default.createElement(
13778
+ return /* @__PURE__ */ import_react29.default.createElement(
13510
13779
  "div",
13511
13780
  {
13512
13781
  className: "fixed inset-0 z-[2200] bg-black/80 backdrop-blur-sm flex items-center justify-center p-2",
13513
13782
  onClick: onClose
13514
13783
  },
13515
- /* @__PURE__ */ import_react30.default.createElement(
13784
+ /* @__PURE__ */ import_react29.default.createElement(
13516
13785
  "div",
13517
13786
  {
13518
- className: "bg-slate-950 border border-white/10 rounded-xl w-[90vw] max-w-[1200px] h-[90vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
13787
+ className: "bg-slate-950 border border-white/10 rounded-xl w-full max-w-[calc(100vw-32px)] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
13519
13788
  onClick: (e) => e.stopPropagation()
13520
13789
  },
13521
- /* @__PURE__ */ import_react30.default.createElement("div", { className: "h-14 px-6 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react30.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, /* @__PURE__ */ import_react30.default.createElement(
13790
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react29.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLayers, { className: "text-indigo-400" }), "Boards"), saveStatus !== "idle" && /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(
13522
13791
  import_fi23.FiLoader,
13523
13792
  {
13524
13793
  className: "animate-spin text-indigo-400",
13525
13794
  size: 12
13526
13795
  }
13527
- ), /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, /* @__PURE__ */ import_react30.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ import_react30.default.createElement(
13796
+ ), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(
13528
13797
  "button",
13529
13798
  {
13530
- onClick: handleAddRootGroup,
13531
- className: "\n flex items-center gap-2 px-3 py-1.5 \n bg-white/5 hover:bg-white/10 \n border border-white/10 hover:border-white/20\n backdrop-blur-sm\n text-slate-200 hover:text-white\n rounded-md transition-all duration-200\n text-xs font-medium shadow-sm\n "
13799
+ onClick: () => handleAddItem("folder"),
13800
+ className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
13532
13801
  },
13533
- /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiPlus, { size: 14, className: "text-indigo-400" }),
13534
- /* @__PURE__ */ import_react30.default.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
13535
- ), /* @__PURE__ */ import_react30.default.createElement(
13802
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiPlus, { size: 14, className: "text-amber-400" }),
13803
+ /* @__PURE__ */ import_react29.default.createElement("span", { className: "hidden sm:inline" }, "Pasta")
13804
+ ), /* @__PURE__ */ import_react29.default.createElement(
13805
+ "button",
13806
+ {
13807
+ onClick: () => handleAddItem("text_group"),
13808
+ className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
13809
+ },
13810
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiPlus, { size: 14, className: "text-indigo-400" }),
13811
+ /* @__PURE__ */ import_react29.default.createElement("span", { className: "hidden sm:inline" }, "Texto")
13812
+ )), /* @__PURE__ */ import_react29.default.createElement(
13536
13813
  "button",
13537
13814
  {
13538
13815
  onClick: onClose,
13539
13816
  className: "w-8 h-8 rounded-lg flex items-center justify-center text-slate-400 hover:text-white hover:bg-white/10 transition-colors"
13540
13817
  },
13541
- "\xD7"
13818
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiX, { size: 16 })
13542
13819
  ))),
13543
- /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex flex-1 overflow-hidden bg-slate-900/20" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex flex-col flex-1" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-8 max-w-[900px] mx-auto w-full space-y-6" }, groups.length === 0 ? /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-4 border-2 border-dashed border-white/5 rounded-2xl bg-slate-900/40 p-12" }, /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiLayers, { size: 40, className: "opacity-10 text-indigo-400" }), /* @__PURE__ */ import_react30.default.createElement("div", { className: "text-center space-y-1" }, /* @__PURE__ */ import_react30.default.createElement("p", { className: "text-sm font-medium text-slate-300" }, "Nenhum grupo criado"), /* @__PURE__ */ import_react30.default.createElement("p", { className: "text-xs text-slate-500 max-w-[200px]" }, canEdit ? "Comece organizando sua narrativa criando o primeiro grupo." : "Este board ainda n\xE3o possui conte\xFAdo.")), canEdit && /* @__PURE__ */ import_react30.default.createElement(
13820
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "h-10 px-6 bg-slate-900/40 border-b border-white/5 flex items-center gap-2 text-[10px] uppercase font-bold tracking-widest text-slate-500 overflow-x-auto no-scrollbar whitespace-nowrap" }, /* @__PURE__ */ import_react29.default.createElement(
13544
13821
  "button",
13545
13822
  {
13546
- onClick: handleAddRootGroup,
13547
- className: "mt-2 px-4 py-2 bg-indigo-500/10 hover:bg-indigo-500/20 text-indigo-400 rounded-lg border border-indigo-500/20 transition-all text-xs font-bold uppercase tracking-wider"
13823
+ onClick: navigateHome,
13824
+ className: `hover:text-white transition-colors flex items-center gap-1 ${navigationStack.length === 0 ? "text-indigo-400" : ""}`
13548
13825
  },
13549
- "Criar Primeiro Grupo"
13550
- )) : groups.map((group, index) => /* @__PURE__ */ import_react30.default.createElement(
13551
- GroupItem,
13826
+ "Home"
13827
+ ), currentPath.map((folder, idx) => /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, { key: folder.id }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiChevronRight, { size: 10, className: "shrink-0" }), /* @__PURE__ */ import_react29.default.createElement(
13828
+ "button",
13552
13829
  {
13553
- key: group.id,
13830
+ onClick: () => navigateToBreadcrumb(idx),
13831
+ className: `hover:text-white transition-colors ${idx === currentPath.length - 1 ? "text-indigo-400" : ""}`
13832
+ },
13833
+ folder.name || "Sem Nome"
13834
+ ))), navigationStack.length > 0 && /* @__PURE__ */ import_react29.default.createElement("div", { className: "ml-auto" }, /* @__PURE__ */ import_react29.default.createElement(
13835
+ "button",
13836
+ {
13837
+ onClick: navigateUp,
13838
+ className: "flex items-center gap-1 px-2 py-1 rounded bg-white/5 hover:bg-white/10 text-slate-400 hover:text-white transition-all"
13839
+ },
13840
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowLeft, { size: 10 }),
13841
+ /* @__PURE__ */ import_react29.default.createElement("span", null, "Voltar")
13842
+ ))),
13843
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex-1 overflow-y-auto overflow-x-hidden custom-scrollbar bg-slate-950/30 p-6 space-y-4" }, currentBoardItems.length === 0 ? /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl bg-slate-900/20" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react29.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, "Esta pasta est\xE1 vazia.", /* @__PURE__ */ import_react29.default.createElement("br", null), "Use os bot\xF5es acima para criar conte\xFAdo.") : /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, "Nenhum conte\xFAdo dispon\xEDvel nesta pasta."))) : currentBoardItems.map((item, index) => /* @__PURE__ */ import_react29.default.createElement(
13844
+ BoardItem,
13845
+ {
13846
+ key: item.id,
13554
13847
  index,
13555
- group,
13556
- onUpdate: handleUpdateGroup,
13557
- onDelete: handleDeleteGroup,
13848
+ prevItem: currentBoardItems[index - 1],
13849
+ nextItem: currentBoardItems[index + 1],
13850
+ item,
13851
+ onUpdate: handleUpdateItem,
13852
+ onDelete: handleDeleteItem,
13558
13853
  onAddSubgroup: handleAddSubgroup,
13559
13854
  onIndent: handleIndent,
13855
+ onIndentDown: handleIndentDown,
13560
13856
  onOutdent: handleOutdent,
13561
- onPlayAncestry: handlePlayFromGroup,
13562
- availableMentionItems,
13563
- canEdit
13857
+ onMoveUp: handleMoveUp,
13858
+ onMoveDown: handleMoveDown,
13859
+ searchItems: allSearchableItems,
13860
+ onMentionClick: handleMentionClick,
13861
+ onEnterFolder: navigateTo,
13862
+ canEdit,
13863
+ isAtRoot: navigationStack.length === 0
13564
13864
  }
13565
- ))))),
13566
- /* @__PURE__ */ import_react30.default.createElement("div", { className: "px-6 py-3 border-t border-white/10 bg-slate-950/50 text-[10px] uppercase tracking-widest font-bold text-slate-600 flex justify-between items-center flex-shrink-0" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react30.default.createElement("span", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "w-1.5 h-1.5 rounded-full bg-indigo-500" }), " ", availableMentionItems.length, " RECURSOS DISPON\xCDVEIS"), /* @__PURE__ */ import_react30.default.createElement("span", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500" }), " ", groups.length, " GRUPOS PRINCIPAIS")), /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-slate-700" }, "X.VIEW :: ANCESTRY BOARD ENGINE"))
13865
+ ))),
13866
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-end flex-shrink-0" }, /* @__PURE__ */ import_react29.default.createElement("span", null, currentBoardItems.length, " itens nesta visualiza\xE7\xE3o"))
13567
13867
  )
13568
13868
  );
13569
13869
  }
13570
13870
 
13571
13871
  // src/components/MilestoneManager.jsx
13572
- var import_react31 = __toESM(require("react"));
13872
+ var import_react30 = __toESM(require("react"));
13573
13873
  var import_fi24 = require("react-icons/fi");
13574
13874
  function MilestoneManager({
13575
13875
  isOpen,
@@ -13578,7 +13878,7 @@ function MilestoneManager({
13578
13878
  onUpdateMilestones = () => {
13579
13879
  }
13580
13880
  }) {
13581
- const [newMilestoneName, setNewMilestoneName] = (0, import_react31.useState)("");
13881
+ const [newMilestoneName, setNewMilestoneName] = (0, import_react30.useState)("");
13582
13882
  const handleAddMilestone = () => {
13583
13883
  if (!newMilestoneName.trim()) return;
13584
13884
  const newMilestone = {
@@ -13603,27 +13903,27 @@ function MilestoneManager({
13603
13903
  };
13604
13904
  if (!isOpen) return null;
13605
13905
  const swallow = (e) => e.stopPropagation();
13606
- return /* @__PURE__ */ import_react31.default.createElement(
13906
+ return /* @__PURE__ */ import_react30.default.createElement(
13607
13907
  "div",
13608
13908
  {
13609
13909
  className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-950/40 backdrop-blur-sm animate-in fade-in duration-300",
13610
13910
  onClick: onClose
13611
13911
  },
13612
- /* @__PURE__ */ import_react31.default.createElement(
13912
+ /* @__PURE__ */ import_react30.default.createElement(
13613
13913
  "div",
13614
13914
  {
13615
13915
  className: "w-full max-w-lg bg-slate-900/90 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl flex flex-col max-h-[85vh] animate-in zoom-in-95 duration-300",
13616
13916
  onClick: swallow
13617
13917
  },
13618
- /* @__PURE__ */ import_react31.default.createElement("div", { className: "px-6 py-4 border-b border-white/10 flex items-center justify-between" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "p-2 rounded-lg bg-indigo-500/20 text-indigo-400" }, /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiTarget, { size: 20 })), /* @__PURE__ */ import_react31.default.createElement("div", null, /* @__PURE__ */ import_react31.default.createElement("h2", { className: "text-lg font-semibold text-slate-100" }, "Milestones"), /* @__PURE__ */ import_react31.default.createElement("p", { className: "text-xs text-slate-400" }, "Gerencie os marcos do seu cen\xE1rio"))), /* @__PURE__ */ import_react31.default.createElement(
13918
+ /* @__PURE__ */ import_react30.default.createElement("div", { className: "px-6 py-4 border-b border-white/10 flex items-center justify-between" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "p-2 rounded-lg bg-indigo-500/20 text-indigo-400" }, /* @__PURE__ */ import_react30.default.createElement(import_fi24.FiTarget, { size: 20 })), /* @__PURE__ */ import_react30.default.createElement("div", null, /* @__PURE__ */ import_react30.default.createElement("h2", { className: "text-lg font-semibold text-slate-100" }, "Milestones"), /* @__PURE__ */ import_react30.default.createElement("p", { className: "text-xs text-slate-400" }, "Gerencie os marcos do seu cen\xE1rio"))), /* @__PURE__ */ import_react30.default.createElement(
13619
13919
  "button",
13620
13920
  {
13621
13921
  onClick: onClose,
13622
13922
  className: "p-2 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition-colors"
13623
13923
  },
13624
- /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiX, { size: 20 })
13924
+ /* @__PURE__ */ import_react30.default.createElement(import_fi24.FiX, { size: 20 })
13625
13925
  )),
13626
- /* @__PURE__ */ import_react31.default.createElement("div", { className: "px-6 py-5 bg-white/5 border-b border-white/5" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ import_react31.default.createElement(
13926
+ /* @__PURE__ */ import_react30.default.createElement("div", { className: "px-6 py-5 bg-white/5 border-b border-white/5" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ import_react30.default.createElement(
13627
13927
  "input",
13628
13928
  {
13629
13929
  type: "text",
@@ -13633,47 +13933,47 @@ function MilestoneManager({
13633
13933
  placeholder: "Adicionar novo milestone...",
13634
13934
  className: "flex-1 bg-slate-800/50 border border-white/10 rounded-xl px-4 py-2.5 text-sm text-slate-100 placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/40 focus:border-indigo-500/50 transition-all shadow-inner"
13635
13935
  }
13636
- ), /* @__PURE__ */ import_react31.default.createElement(
13936
+ ), /* @__PURE__ */ import_react30.default.createElement(
13637
13937
  "button",
13638
13938
  {
13639
13939
  onClick: handleAddMilestone,
13640
13940
  disabled: !newMilestoneName.trim(),
13641
13941
  className: "px-4 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 disabled:opacity-30 disabled:cursor-not-allowed text-white text-sm font-medium transition-all flex items-center gap-2 shadow-lg shadow-indigo-500/20 active:scale-95"
13642
13942
  },
13643
- /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiPlus, { size: 18 }),
13943
+ /* @__PURE__ */ import_react30.default.createElement(import_fi24.FiPlus, { size: 18 }),
13644
13944
  "Adicionar"
13645
13945
  ))),
13646
- /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex-1 overflow-y-auto px-6 py-4 custom-scrollbar" }, milestones.length > 0 ? /* @__PURE__ */ import_react31.default.createElement("div", { className: "space-y-3" }, milestones.map((ms) => /* @__PURE__ */ import_react31.default.createElement(
13946
+ /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex-1 overflow-y-auto px-6 py-4 custom-scrollbar" }, milestones.length > 0 ? /* @__PURE__ */ import_react30.default.createElement("div", { className: "space-y-3" }, milestones.map((ms) => /* @__PURE__ */ import_react30.default.createElement(
13647
13947
  "div",
13648
13948
  {
13649
13949
  key: ms.id,
13650
13950
  className: `group flex items-center justify-between p-4 rounded-xl border transition-all duration-200 ${ms.status === "active" ? "bg-slate-800/40 border-indigo-500/20 hover:border-indigo-500/40" : "bg-slate-900/40 border-white/5 opacity-60 grayscale-[0.3]"}`
13651
13951
  },
13652
- /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ import_react31.default.createElement(
13952
+ /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ import_react30.default.createElement(
13653
13953
  "div",
13654
13954
  {
13655
13955
  className: `w-2 h-2 rounded-full shrink-0 ${ms.status === "active" ? "bg-indigo-400 shadow-[0_0_8px_rgba(129,140,248,0.6)]" : "bg-slate-600"}`
13656
13956
  }
13657
- ), /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ import_react31.default.createElement("span", { className: `text-sm font-medium truncate ${ms.status === "active" ? "text-slate-100" : "text-slate-400 line-through"}` }, ms.name), /* @__PURE__ */ import_react31.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, ms.status === "active" ? "Ativo" : "Inativo"))),
13658
- /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react31.default.createElement(
13957
+ ), /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ import_react30.default.createElement("span", { className: `text-sm font-medium truncate ${ms.status === "active" ? "text-slate-100" : "text-slate-400 line-through"}` }, ms.name), /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, ms.status === "active" ? "Ativo" : "Inativo"))),
13958
+ /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react30.default.createElement(
13659
13959
  "button",
13660
13960
  {
13661
13961
  onClick: () => handleToggleMilestoneStatus(ms.id),
13662
13962
  className: `p-2 rounded-lg transition-all ${ms.status === "active" ? "hover:bg-slate-700 text-slate-400" : "hover:bg-indigo-500/20 text-indigo-400"}`,
13663
13963
  title: ms.status === "active" ? "Inativar" : "Ativar"
13664
13964
  },
13665
- ms.status === "active" ? /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiPauseCircle, { size: 18 }) : /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiPlayCircle, { size: 18 })
13666
- ), /* @__PURE__ */ import_react31.default.createElement(
13965
+ ms.status === "active" ? /* @__PURE__ */ import_react30.default.createElement(import_fi24.FiPauseCircle, { size: 18 }) : /* @__PURE__ */ import_react30.default.createElement(import_fi24.FiPlayCircle, { size: 18 })
13966
+ ), /* @__PURE__ */ import_react30.default.createElement(
13667
13967
  "button",
13668
13968
  {
13669
13969
  onClick: () => handleRemoveMilestone(ms.id),
13670
13970
  className: "p-2 rounded-lg hover:bg-red-500/20 text-slate-500 hover:text-red-400 transition-all",
13671
13971
  title: "Remover"
13672
13972
  },
13673
- /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiTrash2, { size: 18 })
13973
+ /* @__PURE__ */ import_react30.default.createElement(import_fi24.FiTrash2, { size: 18 })
13674
13974
  ))
13675
- ))) : /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex flex-col items-center justify-center py-12 text-center" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "p-4 rounded-full bg-slate-800/30 text-slate-600 mb-4" }, /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiTarget, { size: 40 })), /* @__PURE__ */ import_react31.default.createElement("h3", { className: "text-slate-400 font-medium" }, "Nenhum milestone definido"), /* @__PURE__ */ import_react31.default.createElement("p", { className: "text-xs text-slate-600 max-w-[200px] mt-1 italic" }, "Defina marcos importantes para orientar o progresso do projeto."))),
13676
- /* @__PURE__ */ import_react31.default.createElement("div", { className: "px-6 py-4 border-t border-white/5 bg-slate-900/50 flex items-center justify-between rounded-b-2xl" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex gap-4" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react31.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Total:"), /* @__PURE__ */ import_react31.default.createElement("span", { className: "text-xs font-bold text-slate-300" }, milestones.length)), /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react31.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Ativos:"), /* @__PURE__ */ import_react31.default.createElement("span", { className: "text-xs font-bold text-indigo-400" }, milestones.filter((m) => m.status === "active").length))))
13975
+ ))) : /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex flex-col items-center justify-center py-12 text-center" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "p-4 rounded-full bg-slate-800/30 text-slate-600 mb-4" }, /* @__PURE__ */ import_react30.default.createElement(import_fi24.FiTarget, { size: 40 })), /* @__PURE__ */ import_react30.default.createElement("h3", { className: "text-slate-400 font-medium" }, "Nenhum milestone definido"), /* @__PURE__ */ import_react30.default.createElement("p", { className: "text-xs text-slate-600 max-w-[200px] mt-1 italic" }, "Defina marcos importantes para orientar o progresso do projeto."))),
13976
+ /* @__PURE__ */ import_react30.default.createElement("div", { className: "px-6 py-4 border-t border-white/5 bg-slate-900/50 flex items-center justify-between rounded-b-2xl" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex gap-4" }, /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Total:"), /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-xs font-bold text-slate-300" }, milestones.length)), /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Ativos:"), /* @__PURE__ */ import_react30.default.createElement("span", { className: "text-xs font-bold text-indigo-400" }, milestones.filter((m) => m.status === "active").length))))
13677
13977
  )
13678
13978
  );
13679
13979
  }
@@ -13752,20 +14052,20 @@ function XViewScene({
13752
14052
  get_ancestry_file,
13753
14053
  import_parent_file_modal_get,
13754
14054
  add_new_parent_file_to_scene_at_firebase_action,
13755
- get_ancestry_board_action,
13756
- save_ancestry_board_action,
14055
+ get_boards_action,
14056
+ save_boards_action,
13757
14057
  upload_file_action,
13758
14058
  delete_file_action,
13759
14059
  check_user_permission,
13760
14060
  get_view_members
13761
14061
  }) {
13762
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
13763
- const { data: session, status } = (0, import_react33.useSession)();
14062
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
14063
+ const { data: session, status } = (0, import_react32.useSession)();
13764
14064
  const router = (0, import_navigation.useRouter)();
13765
14065
  const searchParams = (0, import_navigation.useSearchParams)();
13766
14066
  const focusNodeId = searchParams == null ? void 0 : searchParams.get("focus");
13767
14067
  const focusAncestryId = searchParams == null ? void 0 : searchParams.get("ancestry");
13768
- const viewParams = (0, import_react32.useMemo)(() => {
14068
+ const viewParams = (0, import_react31.useMemo)(() => {
13769
14069
  if (encryptedConfig) {
13770
14070
  const data = decryptData(encryptedConfig);
13771
14071
  if (data) {
@@ -13774,7 +14074,7 @@ function XViewScene({
13774
14074
  }
13775
14075
  return null;
13776
14076
  }, [encryptedConfig, session]);
13777
- (0, import_react32.useEffect)(() => {
14077
+ (0, import_react31.useEffect)(() => {
13778
14078
  async function verifyPermission() {
13779
14079
  if (!viewParams || !session || !check_user_permission) return;
13780
14080
  const { id, type, owner_id } = viewParams;
@@ -13811,65 +14111,65 @@ function XViewScene({
13811
14111
  setIsLoading(false);
13812
14112
  }
13813
14113
  }, [viewParams, session, status, check_user_permission]);
13814
- const sceneConfigId = (0, import_react32.useMemo)(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
13815
- const ownerId = (0, import_react32.useMemo)(() => (viewParams == null ? void 0 : viewParams.owner_id) || null, [viewParams]);
13816
- const dbSaveUrl = (0, import_react32.useMemo)(() => {
14114
+ const sceneConfigId = (0, import_react31.useMemo)(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
14115
+ const ownerId = (0, import_react31.useMemo)(() => (viewParams == null ? void 0 : viewParams.owner_id) || null, [viewParams]);
14116
+ const dbSaveUrl = (0, import_react31.useMemo)(() => {
13817
14117
  if (ownerId && sceneConfigId) {
13818
14118
  return `x_view_dbs/${ownerId}/${sceneConfigId}`;
13819
14119
  }
13820
14120
  return null;
13821
14121
  }, [ownerId, sceneConfigId]);
13822
- const sceneSaveUrl = (0, import_react32.useMemo)(() => {
14122
+ const sceneSaveUrl = (0, import_react31.useMemo)(() => {
13823
14123
  if (ownerId && sceneConfigId) {
13824
14124
  return `x_view_scenes/${ownerId}/${sceneConfigId}`;
13825
14125
  }
13826
14126
  return null;
13827
14127
  }, [ownerId, sceneConfigId]);
13828
- const ancestry_save_url = (0, import_react32.useMemo)(() => {
14128
+ const ancestry_save_url = (0, import_react31.useMemo)(() => {
13829
14129
  if (ownerId && sceneConfigId) {
13830
14130
  return `x_view_ancestry/${ownerId}/${sceneConfigId}`;
13831
14131
  }
13832
14132
  return null;
13833
14133
  }, [ownerId, sceneConfigId]);
13834
- const sceneDataRef = (0, import_react32.useRef)(null);
13835
- const parentDataRef = (0, import_react32.useRef)(null);
13836
- const ancestryDataRef = (0, import_react32.useRef)(null);
13837
- const [isLoading, setIsLoading] = (0, import_react32.useState)(true);
13838
- const [permissionStatus, setPermissionStatus] = (0, import_react32.useState)("loading");
13839
- const [userPermissionRole, setUserPermissionRole] = (0, import_react32.useState)(null);
13840
- const [viewMembers, setViewMembers] = (0, import_react32.useState)([]);
13841
- const [isInitialized, setIsInitialized] = (0, import_react32.useState)(false);
13842
- const [sceneVersion, setSceneVersion] = (0, import_react32.useState)(0);
13843
- const [contextMenu, setContextMenu] = (0, import_react32.useState)({
14134
+ const sceneDataRef = (0, import_react31.useRef)(null);
14135
+ const parentDataRef = (0, import_react31.useRef)(null);
14136
+ const ancestryDataRef = (0, import_react31.useRef)(null);
14137
+ const [isLoading, setIsLoading] = (0, import_react31.useState)(true);
14138
+ const [permissionStatus, setPermissionStatus] = (0, import_react31.useState)("loading");
14139
+ const [userPermissionRole, setUserPermissionRole] = (0, import_react31.useState)(null);
14140
+ const [viewMembers, setViewMembers] = (0, import_react31.useState)([]);
14141
+ const [isInitialized, setIsInitialized] = (0, import_react31.useState)(false);
14142
+ const [sceneVersion, setSceneVersion] = (0, import_react31.useState)(0);
14143
+ const [contextMenu, setContextMenu] = (0, import_react31.useState)({
13844
14144
  visible: false,
13845
14145
  x: 0,
13846
14146
  y: 0,
13847
14147
  nodeData: null
13848
14148
  });
13849
- const [multiContextMenu, setMultiContextMenu] = (0, import_react32.useState)({
14149
+ const [multiContextMenu, setMultiContextMenu] = (0, import_react31.useState)({
13850
14150
  visible: false,
13851
14151
  x: 0,
13852
14152
  y: 0,
13853
14153
  nodeIds: null
13854
14154
  });
13855
- const [relationshipMenu, setRelationshipMenu] = (0, import_react32.useState)({
14155
+ const [relationshipMenu, setRelationshipMenu] = (0, import_react31.useState)({
13856
14156
  visible: false,
13857
14157
  x: 0,
13858
14158
  y: 0,
13859
14159
  linkObject: null
13860
14160
  });
13861
- const [creationMode, setCreationMode] = (0, import_react32.useState)({
14161
+ const [creationMode, setCreationMode] = (0, import_react31.useState)({
13862
14162
  isActive: false,
13863
14163
  sourceNodeData: null
13864
14164
  });
13865
- const [versionMode, setVersionMode] = (0, import_react32.useState)({
14165
+ const [versionMode, setVersionMode] = (0, import_react31.useState)({
13866
14166
  isActive: false,
13867
14167
  sourceNodeData: null
13868
14168
  });
13869
- const [questMode, setQuestMode] = (0, import_react32.useState)({ isActive: false });
13870
- const [hasFocusedInitial, setHasFocusedInitial] = (0, import_react32.useState)(false);
13871
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0, import_react32.useState)(false);
13872
- const [ancestryMode, setAncestryMode] = (0, import_react32.useState)({
14169
+ const [questMode, setQuestMode] = (0, import_react31.useState)({ isActive: false });
14170
+ const [hasFocusedInitial, setHasFocusedInitial] = (0, import_react31.useState)(false);
14171
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0, import_react31.useState)(false);
14172
+ const [ancestryMode, setAncestryMode] = (0, import_react31.useState)({
13873
14173
  isActive: false,
13874
14174
  tree: null,
13875
14175
  selectedParentId: null,
@@ -13880,42 +14180,42 @@ function XViewScene({
13880
14180
  ancestryDescriptionSections: [],
13881
14181
  isAddingNodes: false
13882
14182
  });
13883
- const [readingMode, setReadingMode] = (0, import_react32.useState)({
14183
+ const [readingMode, setReadingMode] = (0, import_react31.useState)({
13884
14184
  isActive: false,
13885
14185
  ancestry: null,
13886
14186
  branchStack: [],
13887
14187
  autoAbstraction: false
13888
14188
  });
13889
- const [formPosition, setFormPosition] = (0, import_react32.useState)({
14189
+ const [formPosition, setFormPosition] = (0, import_react31.useState)({
13890
14190
  left: 16,
13891
14191
  top: 16,
13892
14192
  opacity: 0
13893
14193
  });
13894
- const [detailsNode, setDetailsNode] = (0, import_react32.useState)(null);
13895
- const [detailsLink, setDetailsLink] = (0, import_react32.useState)(null);
13896
- const [ancestryLinkDetails, setAncestryLinkDetails] = (0, import_react32.useState)(null);
13897
- const [imageViewer, setImageViewer] = (0, import_react32.useState)({
14194
+ const [detailsNode, setDetailsNode] = (0, import_react31.useState)(null);
14195
+ const [detailsLink, setDetailsLink] = (0, import_react31.useState)(null);
14196
+ const [ancestryLinkDetails, setAncestryLinkDetails] = (0, import_react31.useState)(null);
14197
+ const [imageViewer, setImageViewer] = (0, import_react31.useState)({
13898
14198
  visible: false,
13899
14199
  images: [],
13900
14200
  startIndex: 0
13901
14201
  });
13902
- const [editingAncestryRel, setEditingAncestryRel] = (0, import_react32.useState)({
14202
+ const [editingAncestryRel, setEditingAncestryRel] = (0, import_react31.useState)({
13903
14203
  visible: false,
13904
14204
  data: null,
13905
14205
  path: null
13906
14206
  });
13907
- const [isImportModalOpen, setIsImportModalOpen] = (0, import_react32.useState)(false);
13908
- const [importSuccessMessage, setImportSuccessMessage] = (0, import_react32.useState)("");
13909
- const [invalidTargetError, setInvalidTargetError] = (0, import_react32.useState)(null);
13910
- const [highlightedNodeId, setHighlightedNodeId] = (0, import_react32.useState)(null);
13911
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = (0, import_react32.useState)(false);
13912
- const [ancestryBoardData, setAncestryBoardData] = (0, import_react32.useState)([]);
13913
- const [isSidebarOpen, setIsSidebarOpen] = (0, import_react32.useState)(false);
13914
- const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] = (0, import_react32.useState)(false);
13915
- const mountRef = (0, import_react32.useRef)(null);
13916
- const tooltipRef = (0, import_react32.useRef)(null);
13917
- const formRef = (0, import_react32.useRef)(null);
13918
- const stateRef = (0, import_react32.useRef)({
14207
+ const [isImportModalOpen, setIsImportModalOpen] = (0, import_react31.useState)(false);
14208
+ const [importSuccessMessage, setImportSuccessMessage] = (0, import_react31.useState)("");
14209
+ const [invalidTargetError, setInvalidTargetError] = (0, import_react31.useState)(null);
14210
+ const [highlightedNodeId, setHighlightedNodeId] = (0, import_react31.useState)(null);
14211
+ const [isBoardsOpen, setIsBoardsOpen] = (0, import_react31.useState)(false);
14212
+ const [boardItems, setBoardItems] = (0, import_react31.useState)([]);
14213
+ const [isSidebarOpen, setIsSidebarOpen] = (0, import_react31.useState)(false);
14214
+ const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] = (0, import_react31.useState)(false);
14215
+ const mountRef = (0, import_react31.useRef)(null);
14216
+ const tooltipRef = (0, import_react31.useRef)(null);
14217
+ const formRef = (0, import_react31.useRef)(null);
14218
+ const stateRef = (0, import_react31.useRef)({
13919
14219
  readMode: {
13920
14220
  currentMaxIndex: 0,
13921
14221
  progressMap: {}
@@ -13979,10 +14279,10 @@ function XViewScene({
13979
14279
  minWidth: 320,
13980
14280
  maxWidth: maxReadPanelW
13981
14281
  });
13982
- (0, import_react32.useEffect)(() => {
14282
+ (0, import_react31.useEffect)(() => {
13983
14283
  stateRef.current.ancestry = ancestryMode;
13984
14284
  }, [ancestryMode]);
13985
- (0, import_react32.useEffect)(() => {
14285
+ (0, import_react31.useEffect)(() => {
13986
14286
  var _a2;
13987
14287
  if (!isInitialized) return;
13988
14288
  const map = /* @__PURE__ */ new Map();
@@ -14005,10 +14305,10 @@ function XViewScene({
14005
14305
  }
14006
14306
  stateRef.current.nodeIdToParentFileMap = map;
14007
14307
  }, [isInitialized, sceneVersion]);
14008
- const handleNavigateBack = (0, import_react32.useCallback)(() => {
14308
+ const handleNavigateBack = (0, import_react31.useCallback)(() => {
14009
14309
  router.push("/dashboard/scenes");
14010
14310
  }, [router]);
14011
- const handleConfirmImport = (0, import_react32.useCallback)(
14311
+ const handleConfirmImport = (0, import_react31.useCallback)(
14012
14312
  async (importPayload) => {
14013
14313
  var _a2, _b2;
14014
14314
  let files = [];
@@ -14136,7 +14436,7 @@ function XViewScene({
14136
14436
  const handleOpenImageViewer = (images, startIndex) => {
14137
14437
  setImageViewer({ visible: true, images, startIndex });
14138
14438
  };
14139
- const tweenToTarget = (0, import_react32.useCallback)(
14439
+ const tweenToTarget = (0, import_react31.useCallback)(
14140
14440
  (target, zoomFactor = 1, forcedDirection = null) => {
14141
14441
  const { camera, controls, tweenGroup } = stateRef.current;
14142
14442
  if (!camera || !controls || !tweenGroup) return;
@@ -14162,7 +14462,7 @@ function XViewScene({
14162
14462
  if (!t || typeof t.closest !== "function") return false;
14163
14463
  return !!t.closest(".ui-overlay");
14164
14464
  };
14165
- const buildFullAncestryTree = (0, import_react32.useCallback)(
14465
+ const buildFullAncestryTree = (0, import_react31.useCallback)(
14166
14466
  (idTree, nodes, ancestries = []) => {
14167
14467
  if (!idTree) return null;
14168
14468
  const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
@@ -14247,7 +14547,7 @@ function XViewScene({
14247
14547
  },
14248
14548
  []
14249
14549
  );
14250
- const handleActivateTimeline = (0, import_react32.useCallback)(() => {
14550
+ const handleActivateTimeline = (0, import_react31.useCallback)(() => {
14251
14551
  const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
14252
14552
  if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
14253
14553
  while (timelineIntervalsGroup.children.length > 0) {
@@ -14407,7 +14707,7 @@ function XViewScene({
14407
14707
  }
14408
14708
  });
14409
14709
  }, []);
14410
- const handleVersionTimeline = (0, import_react32.useCallback)((sourceMesh, versionMeshes) => {
14710
+ const handleVersionTimeline = (0, import_react31.useCallback)((sourceMesh, versionMeshes) => {
14411
14711
  const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
14412
14712
  if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
14413
14713
  return;
@@ -14544,7 +14844,7 @@ function XViewScene({
14544
14844
  }
14545
14845
  });
14546
14846
  }, []);
14547
- (0, import_react32.useEffect)(() => {
14847
+ (0, import_react31.useEffect)(() => {
14548
14848
  async function fetchAllData(configPath, ownerId2) {
14549
14849
  var _a2, _b2;
14550
14850
  if (!get_scene_view_data) {
@@ -14563,7 +14863,7 @@ function XViewScene({
14563
14863
  focusNodeId,
14564
14864
  focusAncestryId
14565
14865
  );
14566
- const boardPromise = get_ancestry_board_action && session ? get_ancestry_board_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
14866
+ const boardPromise = get_boards_action && session ? get_boards_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
14567
14867
  const [sceneResponse, boardResponse] = await Promise.all([
14568
14868
  scenePromise,
14569
14869
  boardPromise
@@ -14614,10 +14914,10 @@ function XViewScene({
14614
14914
  (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida."
14615
14915
  );
14616
14916
  }
14617
- if (boardResponse == null ? void 0 : boardResponse.success) {
14618
- setAncestryBoardData(boardResponse.data);
14917
+ if (boardResponse.success && boardResponse.data) {
14918
+ setBoardItems(boardResponse.data);
14619
14919
  } else {
14620
- setAncestryBoardData([]);
14920
+ setBoardItems([]);
14621
14921
  }
14622
14922
  } catch (error) {
14623
14923
  console.error("Erro cr\xEDtico no carregamento inicial:", error);
@@ -14643,18 +14943,18 @@ function XViewScene({
14643
14943
  ownerId,
14644
14944
  viewParams,
14645
14945
  get_scene_view_data,
14646
- get_ancestry_board_action,
14946
+ get_boards_action,
14647
14947
  isInitialized,
14648
14948
  permissionStatus,
14649
14949
  focusNodeId,
14650
14950
  focusAncestryId
14651
14951
  ]);
14652
- const isNodeInView = (0, import_react32.useCallback)((id) => {
14952
+ const isNodeInView = (0, import_react31.useCallback)((id) => {
14653
14953
  const key = String(id);
14654
14954
  const objs = stateRef.current.nodeObjects || {};
14655
14955
  return !!objs[key];
14656
14956
  }, []);
14657
- const addOrUpdateNodeMesh = (0, import_react32.useCallback)(
14957
+ const addOrUpdateNodeMesh = (0, import_react31.useCallback)(
14658
14958
  (nodeData, position, suppressVersionUpdate = false, forceShowQuestDate = false) => {
14659
14959
  const {
14660
14960
  graphGroup,
@@ -14695,7 +14995,7 @@ function XViewScene({
14695
14995
  },
14696
14996
  []
14697
14997
  );
14698
- const handleActivateQuestLens = (0, import_react32.useCallback)(({ assigneeId, status: status2, milestoneId }) => {
14998
+ const handleActivateQuestLens = (0, import_react31.useCallback)(({ assigneeId, status: status2, milestoneId }) => {
14699
14999
  var _a2;
14700
15000
  const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
14701
15001
  if (!nodeObjects || !tweenGroup || !graphGroup) return;
@@ -14909,7 +15209,7 @@ function XViewScene({
14909
15209
  camTween.start();
14910
15210
  }
14911
15211
  }, [addOrUpdateNodeMesh]);
14912
- (0, import_react32.useEffect)(() => {
15212
+ (0, import_react31.useEffect)(() => {
14913
15213
  if (!isInitialized || !sceneDataRef.current) return;
14914
15214
  const currentMount = mountRef.current;
14915
15215
  if (!currentMount) return;
@@ -15665,7 +15965,7 @@ function XViewScene({
15665
15965
  get_scene_view_data,
15666
15966
  save_view_data
15667
15967
  ]);
15668
- const handleGhostNodeImageChange = (0, import_react32.useCallback)((useImage, imageUrl) => {
15968
+ const handleGhostNodeImageChange = (0, import_react31.useCallback)((useImage, imageUrl) => {
15669
15969
  const {
15670
15970
  node: ghostNode,
15671
15971
  line: ghostLine,
@@ -15713,7 +16013,7 @@ function XViewScene({
15713
16013
  aura: newGhostNode.getObjectByName("aura")
15714
16014
  };
15715
16015
  }, []);
15716
- const handleGhostNodeIntensityChange = (0, import_react32.useCallback)((newIntensity) => {
16016
+ const handleGhostNodeIntensityChange = (0, import_react31.useCallback)((newIntensity) => {
15717
16017
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
15718
16018
  if (!ghostNode) return;
15719
16019
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -15734,7 +16034,7 @@ function XViewScene({
15734
16034
  ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
15735
16035
  }
15736
16036
  }, []);
15737
- const handleDetailNodeIntensityChange = (0, import_react32.useCallback)(
16037
+ const handleDetailNodeIntensityChange = (0, import_react31.useCallback)(
15738
16038
  (nodeId, newIntensity) => {
15739
16039
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
15740
16040
  if (!mesh) return;
@@ -15890,7 +16190,7 @@ function XViewScene({
15890
16190
  mountRef.current.style.cursor = "default";
15891
16191
  }
15892
16192
  };
15893
- const handleAncestryTreeUpdate = (0, import_react32.useCallback)((newTree, extraData = null) => {
16193
+ const handleAncestryTreeUpdate = (0, import_react31.useCallback)((newTree, extraData = null) => {
15894
16194
  setAncestryMode((prev) => {
15895
16195
  const prevTreeStr = JSON.stringify(prev.tree);
15896
16196
  const newTreeStr = JSON.stringify(newTree);
@@ -15913,7 +16213,7 @@ function XViewScene({
15913
16213
  };
15914
16214
  });
15915
16215
  }, []);
15916
- const actionHandlerContext = (0, import_react32.useMemo)(
16216
+ const actionHandlerContext = (0, import_react31.useMemo)(
15917
16217
  () => {
15918
16218
  var _a2;
15919
16219
  return {
@@ -15974,7 +16274,7 @@ function XViewScene({
15974
16274
  const handleStartVersioning = (nodeData) => {
15975
16275
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
15976
16276
  };
15977
- const handleStartQuestQuick = (0, import_react32.useCallback)((questNode) => {
16277
+ const handleStartQuestQuick = (0, import_react31.useCallback)((questNode) => {
15978
16278
  var _a2, _b2, _c2;
15979
16279
  if (!questNode || !actionHandlerContext) return;
15980
16280
  const allParentNodes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
@@ -16009,7 +16309,7 @@ function XViewScene({
16009
16309
  }
16010
16310
  setDetailsNode(updatedNode);
16011
16311
  }, [session, actionHandlerContext]);
16012
- const handleFinishQuestQuick = (0, import_react32.useCallback)((questNode) => {
16312
+ const handleFinishQuestQuick = (0, import_react31.useCallback)((questNode) => {
16013
16313
  var _a2, _b2, _c2, _d2;
16014
16314
  if (!questNode || !actionHandlerContext) return;
16015
16315
  const {
@@ -16083,7 +16383,7 @@ function XViewScene({
16083
16383
  setDetailsNode(null);
16084
16384
  }
16085
16385
  }, [session, actionHandlerContext, viewMembers, detailsNode]);
16086
- const handleCancelQuest = (0, import_react32.useCallback)(() => {
16386
+ const handleCancelQuest = (0, import_react31.useCallback)(() => {
16087
16387
  const { graphGroup, ghostElements } = stateRef.current;
16088
16388
  if (ghostElements.node && graphGroup) {
16089
16389
  if (ghostElements.node.userData.labelObject) {
@@ -16142,13 +16442,15 @@ function XViewScene({
16142
16442
  try {
16143
16443
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
16144
16444
  sceneDataRef2.current.quest_counter = currentCounter + 1;
16145
- sceneDataRef2.current.quest_nodes = sceneFileData.quest_nodes;
16146
- sceneDataRef2.current.quest_links = sceneFileData.quest_links;
16147
16445
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
16148
16446
  parentFileId: sceneConfigId2,
16149
16447
  ownerId: ownerId2,
16150
16448
  datasetName: "Quests Internas (View)"
16151
16449
  });
16450
+ sceneDataRef2.current.quest_nodes = [...graphDataRef.current[sceneConfigId2].nodes];
16451
+ if (parentDataRef.current[sceneConfigId2]) {
16452
+ parentDataRef.current[sceneConfigId2].nodes = [...graphDataRef.current[sceneConfigId2].nodes];
16453
+ }
16152
16454
  const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
16153
16455
  const { graphGroup, ghostElements } = stateRef2.current;
16154
16456
  if (ghostElements.node && graphGroup) {
@@ -16238,7 +16540,7 @@ function XViewScene({
16238
16540
  }
16239
16541
  userActionHandlers.handleCancelConnection(context);
16240
16542
  };
16241
- const handleClearAncestryVisuals = (0, import_react32.useCallback)((ancestryId) => {
16543
+ const handleClearAncestryVisuals = (0, import_react31.useCallback)((ancestryId) => {
16242
16544
  const { renderedAncestries, ancestryGroup } = stateRef.current;
16243
16545
  const renderIndex = renderedAncestries.findIndex(
16244
16546
  (a) => String(a.id) === String(ancestryId)
@@ -16256,7 +16558,7 @@ function XViewScene({
16256
16558
  );
16257
16559
  }
16258
16560
  }, []);
16259
- const handleRenderAncestry = (0, import_react32.useCallback)(
16561
+ const handleRenderAncestry = (0, import_react31.useCallback)(
16260
16562
  async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
16261
16563
  setContextMenu(
16262
16564
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -16750,7 +17052,7 @@ function XViewScene({
16750
17052
  ancestryMode.isActive
16751
17053
  ]
16752
17054
  );
16753
- const handleRenderAbstractionTree = (0, import_react32.useCallback)(
17055
+ const handleRenderAbstractionTree = (0, import_react31.useCallback)(
16754
17056
  (ancestryObject, targetNodeId = null) => {
16755
17057
  setContextMenu(
16756
17058
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -16838,7 +17140,7 @@ function XViewScene({
16838
17140
  handleClearAncestryVisuals
16839
17141
  ]
16840
17142
  );
16841
- const handleReadModeBranchNav = (0, import_react32.useCallback)(
17143
+ const handleReadModeBranchNav = (0, import_react31.useCallback)(
16842
17144
  (nodeId, action, direction = "right") => {
16843
17145
  const { ancestry, branchStack } = readingMode;
16844
17146
  if (!ancestry || !ancestry.tree) return;
@@ -17016,13 +17318,13 @@ function XViewScene({
17016
17318
  },
17017
17319
  [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]
17018
17320
  );
17019
- const handleReadModeHighlight = (0, import_react32.useCallback)((nodeId) => {
17321
+ const handleReadModeHighlight = (0, import_react31.useCallback)((nodeId) => {
17020
17322
  if (stateRef.current.highlightedNodeId !== nodeId) {
17021
17323
  stateRef.current.highlightedNodeId = nodeId;
17022
17324
  }
17023
17325
  setHighlightedNodeId(nodeId);
17024
17326
  }, []);
17025
- const activeNodeBranches = (0, import_react32.useMemo)(() => {
17327
+ const activeNodeBranches = (0, import_react31.useMemo)(() => {
17026
17328
  if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
17027
17329
  return null;
17028
17330
  const fullTree = buildFullAncestryTree(
@@ -17066,7 +17368,7 @@ function XViewScene({
17066
17368
  readingMode.branchStack,
17067
17369
  ancestryDataRef.current
17068
17370
  ]);
17069
- const backNavigationInfo = (0, import_react32.useMemo)(() => {
17371
+ const backNavigationInfo = (0, import_react31.useMemo)(() => {
17070
17372
  const { branchStack } = readingMode;
17071
17373
  if (!branchStack || branchStack.length === 0) return null;
17072
17374
  const lastStep = branchStack[branchStack.length - 1];
@@ -17077,7 +17379,7 @@ function XViewScene({
17077
17379
  name: "Voltar para anterior"
17078
17380
  };
17079
17381
  }, [readingMode.branchStack]);
17080
- const getReadModeDisplayContext = (0, import_react32.useMemo)(() => {
17382
+ const getReadModeDisplayContext = (0, import_react31.useMemo)(() => {
17081
17383
  const { ancestry, branchStack } = readingMode;
17082
17384
  if (!ancestry) return null;
17083
17385
  if (branchStack.length === 0) {
@@ -17120,7 +17422,7 @@ function XViewScene({
17120
17422
  customProperties: branchProps
17121
17423
  };
17122
17424
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
17123
- const readModeAbstractionTree = (0, import_react32.useMemo)(() => {
17425
+ const readModeAbstractionTree = (0, import_react31.useMemo)(() => {
17124
17426
  if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
17125
17427
  return null;
17126
17428
  }
@@ -17139,7 +17441,7 @@ function XViewScene({
17139
17441
  buildFullAncestryTree,
17140
17442
  sceneVersion
17141
17443
  ]);
17142
- const handleStartReadingAncestry = (0, import_react32.useCallback)(
17444
+ const handleStartReadingAncestry = (0, import_react31.useCallback)(
17143
17445
  async (ancestryObject, renderMode = "full") => {
17144
17446
  setContextMenu(
17145
17447
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -17182,7 +17484,7 @@ function XViewScene({
17182
17484
  },
17183
17485
  [handleRenderAncestry, handleRenderAbstractionTree]
17184
17486
  );
17185
- const handleReadModeSectionChange = (0, import_react32.useCallback)(
17487
+ const handleReadModeSectionChange = (0, import_react31.useCallback)(
17186
17488
  (activeSectionId) => {
17187
17489
  const { ancestry, branchStack } = readingMode;
17188
17490
  if (!ancestry || !readingMode.isActive) return;
@@ -17267,10 +17569,10 @@ function XViewScene({
17267
17569
  ancestryDataRef.current
17268
17570
  ]
17269
17571
  );
17270
- const handleCloseReadMode = (0, import_react32.useCallback)(() => {
17572
+ const handleCloseReadMode = (0, import_react31.useCallback)(() => {
17271
17573
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
17272
17574
  }, []);
17273
- const handleAncestrySectionChange = (0, import_react32.useCallback)(
17575
+ const handleAncestrySectionChange = (0, import_react31.useCallback)(
17274
17576
  (activeSectionId, ancestryOverride = null, rotation = 0) => {
17275
17577
  var _a2, _b2;
17276
17578
  const currentMode = stateRef.current.ancestry;
@@ -17332,7 +17634,7 @@ function XViewScene({
17332
17634
  },
17333
17635
  [handleRenderAncestry]
17334
17636
  );
17335
- const handleEditAncestry = (0, import_react32.useCallback)(
17637
+ const handleEditAncestry = (0, import_react31.useCallback)(
17336
17638
  async (ancestryObject) => {
17337
17639
  setContextMenu(
17338
17640
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -17387,7 +17689,7 @@ function XViewScene({
17387
17689
  const handleSelectAncestryParent = (nodeId) => {
17388
17690
  setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
17389
17691
  };
17390
- const handleRemoveFromAncestry = (0, import_react32.useCallback)((pathToRemove) => {
17692
+ const handleRemoveFromAncestry = (0, import_react31.useCallback)((pathToRemove) => {
17391
17693
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
17392
17694
  console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
17393
17695
  return;
@@ -17412,7 +17714,7 @@ function XViewScene({
17412
17714
  return { ...prev, tree: newTree };
17413
17715
  });
17414
17716
  }, []);
17415
- const handleSaveAncestry = (0, import_react32.useCallback)(
17717
+ const handleSaveAncestry = (0, import_react31.useCallback)(
17416
17718
  async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
17417
17719
  const treeToUse = treeOverride || ancestryMode.tree;
17418
17720
  const { isEditMode, currentAncestryId } = ancestryMode;
@@ -17648,7 +17950,7 @@ function XViewScene({
17648
17950
  });
17649
17951
  setEditingAncestryRel({ visible: false, data: null, path: null });
17650
17952
  };
17651
- const handleDeleteAncestry = (0, import_react32.useCallback)(
17953
+ const handleDeleteAncestry = (0, import_react31.useCallback)(
17652
17954
  async (ancestryIdToDelete) => {
17653
17955
  if (!ancestryIdToDelete) {
17654
17956
  alert("ID da ancestralidade n\xE3o encontrado.");
@@ -17730,42 +18032,84 @@ function XViewScene({
17730
18032
  },
17731
18033
  [save_view_data, delete_file_action]
17732
18034
  );
17733
- const handleOpenAncestryBoard = (0, import_react32.useCallback)(() => {
17734
- setIsAncestryBoardOpen(true);
18035
+ const handleOpenBoards = (0, import_react31.useCallback)(() => {
18036
+ setIsBoardsOpen(true);
17735
18037
  }, []);
17736
- const handleSelectAncestryFromBoard = (0, import_react32.useCallback)(
18038
+ const allAvailableNodes = (0, import_react31.useMemo)(() => {
18039
+ if (!parentDataRef.current) return [];
18040
+ return Object.values(parentDataRef.current).flatMap(
18041
+ (fileData) => fileData.nodes || []
18042
+ );
18043
+ }, [sceneVersion, isInitialized]);
18044
+ const allAvailableAncestries = (0, import_react31.useMemo)(() => {
18045
+ return ancestryDataRef.current || [];
18046
+ }, [sceneVersion, isInitialized]);
18047
+ const handleOpenReference = (0, import_react31.useCallback)(
18048
+ (referenceData) => {
18049
+ const { type, id } = referenceData;
18050
+ if (type === "node") {
18051
+ const targetNode = allAvailableNodes.find(
18052
+ (n) => String(n.id) === String(id)
18053
+ );
18054
+ if (targetNode) {
18055
+ setAncestryLinkDetails(null);
18056
+ setDetailsLink(null);
18057
+ setDetailsNode(targetNode);
18058
+ const sceneMesh = stateRef.current.nodeObjects[String(id)];
18059
+ if (sceneMesh) {
18060
+ tweenToTarget(sceneMesh);
18061
+ }
18062
+ } else {
18063
+ alert("Node original n\xE3o encontrado neste contexto.");
18064
+ }
18065
+ } else if (type === "ancestry") {
18066
+ const targetAncestry = allAvailableAncestries.find(
18067
+ (a) => String(a.ancestry_id) === String(id)
18068
+ );
18069
+ if (targetAncestry) {
18070
+ setDetailsNode(null);
18071
+ setDetailsLink(null);
18072
+ setAncestryLinkDetails(null);
18073
+ handleEditAncestry(targetAncestry);
18074
+ } else {
18075
+ alert("Ancestralidade original n\xE3o encontrada neste contexto.");
18076
+ }
18077
+ }
18078
+ },
18079
+ [
18080
+ allAvailableNodes,
18081
+ allAvailableAncestries,
18082
+ handleEditAncestry,
18083
+ tweenToTarget
18084
+ ]
18085
+ );
18086
+ const handleSelectAncestryFromBoard = (0, import_react31.useCallback)(
17737
18087
  (item) => {
17738
- setIsAncestryBoardOpen(false);
18088
+ setIsBoardsOpen(false);
17739
18089
  setIsSidebarOpen(false);
17740
- if (item.type === "ancestry" || !item.type) {
18090
+ if (item.type === "ancestry") {
17741
18091
  handleStartReadingAncestry(item);
17742
18092
  } else {
17743
- const nodeId = String(item.id);
17744
- const sceneMesh = stateRef.current.nodeObjects[nodeId];
17745
- if (sceneMesh) {
17746
- tweenToTarget(sceneMesh);
17747
- } else {
17748
- console.warn("Objeto n\xE3o encontrado na cena para foco:", nodeId);
17749
- }
18093
+ handleOpenReference({ type: "node", id: item.id });
17750
18094
  }
17751
18095
  },
17752
- [handleStartReadingAncestry, tweenToTarget]
18096
+ [handleStartReadingAncestry, handleOpenReference]
17753
18097
  );
17754
- const handleSaveAncestryBoard = (0, import_react32.useCallback)(
17755
- async (groups) => {
18098
+ const handleSaveBoards = (0, import_react31.useCallback)(
18099
+ async (boardItems2) => {
17756
18100
  if (!sceneConfigId || !viewParams || !session) return;
17757
18101
  const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
17758
- await save_ancestry_board_action(
18102
+ await save_boards_action(
17759
18103
  sceneConfigId,
17760
18104
  sceneType,
17761
- groups,
18105
+ boardItems2,
17762
18106
  session,
17763
18107
  ownerId
17764
18108
  );
17765
18109
  },
17766
- [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]
18110
+ [sceneConfigId, viewParams, session, save_boards_action, ownerId]
17767
18111
  );
17768
- const existingNodeTypes = (0, import_react32.useMemo)(() => {
18112
+ const existingNodeTypes = (0, import_react31.useMemo)(() => {
17769
18113
  if (!parentDataRef.current) {
17770
18114
  return [];
17771
18115
  }
@@ -17777,28 +18121,22 @@ function XViewScene({
17777
18121
  ).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
17778
18122
  return [...new Set(allTypes)];
17779
18123
  }, [parentDataRef.current, sceneVersion]);
17780
- const searchableDbNodes = (0, import_react32.useMemo)(() => {
17781
- var _a2;
18124
+ const searchableDbNodes = (0, import_react31.useMemo)(() => {
17782
18125
  if (!parentDataRef.current) {
17783
18126
  return [];
17784
18127
  }
17785
- const datasetsPool = Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
18128
+ return Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
17786
18129
  const datasetName = fileData.dataset_name || `Dataset #${dbId.substring(0, 6)}`;
17787
18130
  return (fileData.nodes || []).map((node) => ({
17788
18131
  ...node,
17789
18132
  dataset_name: datasetName
17790
18133
  }));
18134
+ }).filter((node) => {
18135
+ var _a2;
18136
+ return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
17791
18137
  });
17792
- const questsPool = (((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || []).map((node) => ({
17793
- ...node,
17794
- dataset_name: "Quests Internas (View)"
17795
- }));
17796
- return [...datasetsPool, ...questsPool].filter((node) => {
17797
- var _a3;
17798
- return !((_a3 = node.version_node) == null ? void 0 : _a3.is_version);
17799
- });
17800
- }, [parentDataRef.current, (_b = sceneDataRef.current) == null ? void 0 : _b.quest_nodes, sceneVersion]);
17801
- const handleAddExistingNode = (0, import_react32.useCallback)(
18138
+ }, [parentDataRef.current, sceneVersion]);
18139
+ const handleAddExistingNode = (0, import_react31.useCallback)(
17802
18140
  (nodeId) => {
17803
18141
  return userActionHandlers.handleAddExistingNodeById(
17804
18142
  actionHandlerContext,
@@ -17807,7 +18145,7 @@ function XViewScene({
17807
18145
  },
17808
18146
  [actionHandlerContext]
17809
18147
  );
17810
- const handleUpdateMilestones = (0, import_react32.useCallback)(
18148
+ const handleUpdateMilestones = (0, import_react31.useCallback)(
17811
18149
  async (newMilestones) => {
17812
18150
  var _a2, _b2, _c2;
17813
18151
  if (!sceneDataRef.current) return;
@@ -17853,7 +18191,7 @@ function XViewScene({
17853
18191
  viewParams == null ? void 0 : viewParams.type
17854
18192
  ]
17855
18193
  );
17856
- const handleSaveCurrentView = (0, import_react32.useCallback)(async () => {
18194
+ const handleSaveCurrentView = (0, import_react31.useCallback)(async () => {
17857
18195
  var _a2, _b2, _c2;
17858
18196
  const { nodeObjects, allLinks } = stateRef.current;
17859
18197
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
@@ -17896,61 +18234,13 @@ function XViewScene({
17896
18234
  console.error("Erro na chamada de save_view_data:", error);
17897
18235
  }
17898
18236
  }, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
17899
- const allAvailableNodes = (0, import_react32.useMemo)(() => {
17900
- if (!parentDataRef.current) return [];
17901
- return Object.values(parentDataRef.current).flatMap(
17902
- (fileData) => fileData.nodes || []
17903
- );
17904
- }, [sceneVersion, isInitialized]);
17905
- const allAvailableAncestries = (0, import_react32.useMemo)(() => {
17906
- return ancestryDataRef.current || [];
17907
- }, [sceneVersion, isInitialized]);
17908
- const handleOpenReference = (0, import_react32.useCallback)(
17909
- (referenceData) => {
17910
- const { type, id } = referenceData;
17911
- if (type === "node") {
17912
- const targetNode = allAvailableNodes.find(
17913
- (n) => String(n.id) === String(id)
17914
- );
17915
- if (targetNode) {
17916
- setAncestryLinkDetails(null);
17917
- setDetailsLink(null);
17918
- setDetailsNode(targetNode);
17919
- const sceneMesh = stateRef.current.nodeObjects[String(id)];
17920
- if (sceneMesh) {
17921
- tweenToTarget(sceneMesh);
17922
- }
17923
- } else {
17924
- alert("Node original n\xE3o encontrado neste contexto.");
17925
- }
17926
- } else if (type === "ancestry") {
17927
- const targetAncestry = allAvailableAncestries.find(
17928
- (a) => String(a.ancestry_id) === String(id)
17929
- );
17930
- if (targetAncestry) {
17931
- setDetailsNode(null);
17932
- setDetailsLink(null);
17933
- setAncestryLinkDetails(null);
17934
- handleEditAncestry(targetAncestry);
17935
- } else {
17936
- alert("Ancestralidade original n\xE3o encontrada neste contexto.");
17937
- }
17938
- }
17939
- },
17940
- [
17941
- allAvailableNodes,
17942
- allAvailableAncestries,
17943
- handleEditAncestry,
17944
- tweenToTarget
17945
- ]
17946
- );
17947
- const handleToggleAncestryAddMode = (0, import_react32.useCallback)(() => {
18237
+ const handleToggleAncestryAddMode = (0, import_react31.useCallback)(() => {
17948
18238
  setAncestryMode((prev) => ({
17949
18239
  ...prev,
17950
18240
  isAddingNodes: !prev.isAddingNodes
17951
18241
  }));
17952
18242
  }, []);
17953
- const handleFocusNode = (0, import_react32.useCallback)(
18243
+ const handleFocusNode = (0, import_react31.useCallback)(
17954
18244
  (nodeData) => {
17955
18245
  var _a2;
17956
18246
  if (!nodeData) return;
@@ -17966,7 +18256,7 @@ function XViewScene({
17966
18256
  },
17967
18257
  [tweenToTarget]
17968
18258
  );
17969
- const availableDatasets = (0, import_react32.useMemo)(() => {
18259
+ const availableDatasets = (0, import_react31.useMemo)(() => {
17970
18260
  if (!sceneDataRef.current || !parentDataRef.current) return [];
17971
18261
  return sceneDataRef.current.parent_dbs.map((db) => {
17972
18262
  var _a2;
@@ -17976,11 +18266,11 @@ function XViewScene({
17976
18266
  };
17977
18267
  });
17978
18268
  }, [sceneVersion, isInitialized]);
17979
- const sourceNodeDatasetId = creationMode.sourceNodeData ? (_c = stateRef.current.nodeIdToParentFileMap.get(
18269
+ const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
17980
18270
  String(creationMode.sourceNodeData.id)
17981
- )) == null ? void 0 : _c.parentFileId : null;
18271
+ )) == null ? void 0 : _b.parentFileId : null;
17982
18272
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
17983
- (0, import_react32.useEffect)(() => {
18273
+ (0, import_react31.useEffect)(() => {
17984
18274
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
17985
18275
  const nodeObjects = stateRef.current.nodeObjects || {};
17986
18276
  const targetMesh = nodeObjects[String(focusNodeId)];
@@ -18003,7 +18293,7 @@ function XViewScene({
18003
18293
  hasFocusedInitial,
18004
18294
  tweenToTarget
18005
18295
  ]);
18006
- (0, import_react32.useEffect)(() => {
18296
+ (0, import_react31.useEffect)(() => {
18007
18297
  if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
18008
18298
  const ancestries = ancestryDataRef.current || [];
18009
18299
  const targetAncestry = ancestries.find(
@@ -18028,7 +18318,7 @@ function XViewScene({
18028
18318
  hasOpenedInitialAncestry,
18029
18319
  handleStartReadingAncestry
18030
18320
  ]);
18031
- (0, import_react32.useEffect)(() => {
18321
+ (0, import_react31.useEffect)(() => {
18032
18322
  function handleKeyDown(event) {
18033
18323
  var _a2, _b2, _c2;
18034
18324
  const context = actionHandlerContext;
@@ -18068,7 +18358,7 @@ function XViewScene({
18068
18358
  setRelationshipMenu((prev) => ({ ...prev, visible: false }));
18069
18359
  }
18070
18360
  if (event.key.toLowerCase() === "q") {
18071
- const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
18361
+ const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isBoardsOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
18072
18362
  if (isUiClear) {
18073
18363
  const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
18074
18364
  if (!isView) return;
@@ -18137,7 +18427,7 @@ function XViewScene({
18137
18427
  relationshipMenu.visible,
18138
18428
  readingMode.isActive,
18139
18429
  isImportModalOpen,
18140
- isAncestryBoardOpen,
18430
+ isBoardsOpen,
18141
18431
  isSidebarOpen,
18142
18432
  detailsNode,
18143
18433
  detailsLink,
@@ -18151,10 +18441,10 @@ function XViewScene({
18151
18441
  // <-- handleCancelQuest adicionado aqui
18152
18442
  ]);
18153
18443
  if (isLoading || status === "loading" || permissionStatus === "loading") {
18154
- return /* @__PURE__ */ import_react32.default.createElement(LoadingScreen, null);
18444
+ return /* @__PURE__ */ import_react31.default.createElement(LoadingScreen, null);
18155
18445
  }
18156
18446
  if (permissionStatus === "denied") {
18157
- return /* @__PURE__ */ import_react32.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react32.default.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ import_react32.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react32.default.createElement(
18447
+ return /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ import_react31.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react31.default.createElement(
18158
18448
  "svg",
18159
18449
  {
18160
18450
  xmlns: "http://www.w3.org/2000/svg",
@@ -18164,7 +18454,7 @@ function XViewScene({
18164
18454
  stroke: "currentColor",
18165
18455
  className: "w-16 h-16 mx-auto"
18166
18456
  },
18167
- /* @__PURE__ */ import_react32.default.createElement(
18457
+ /* @__PURE__ */ import_react31.default.createElement(
18168
18458
  "path",
18169
18459
  {
18170
18460
  strokeLinecap: "round",
@@ -18172,13 +18462,13 @@ function XViewScene({
18172
18462
  d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
18173
18463
  }
18174
18464
  )
18175
- )), /* @__PURE__ */ import_react32.default.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ import_react32.default.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ import_react32.default.createElement(
18465
+ )), /* @__PURE__ */ import_react31.default.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ import_react31.default.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ import_react31.default.createElement(
18176
18466
  "button",
18177
18467
  {
18178
18468
  onClick: () => router.push("/dashboard/scenes"),
18179
18469
  className: "flex items-center justify-center gap-2 w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors font-medium"
18180
18470
  },
18181
- /* @__PURE__ */ import_react32.default.createElement(
18471
+ /* @__PURE__ */ import_react31.default.createElement(
18182
18472
  "svg",
18183
18473
  {
18184
18474
  xmlns: "http://www.w3.org/2000/svg",
@@ -18188,7 +18478,7 @@ function XViewScene({
18188
18478
  stroke: "currentColor",
18189
18479
  className: "w-5 h-5"
18190
18480
  },
18191
- /* @__PURE__ */ import_react32.default.createElement(
18481
+ /* @__PURE__ */ import_react31.default.createElement(
18192
18482
  "path",
18193
18483
  {
18194
18484
  strokeLinecap: "round",
@@ -18200,7 +18490,7 @@ function XViewScene({
18200
18490
  "Voltar para Scenes"
18201
18491
  )));
18202
18492
  }
18203
- return /* @__PURE__ */ import_react32.default.createElement(
18493
+ return /* @__PURE__ */ import_react31.default.createElement(
18204
18494
  "div",
18205
18495
  {
18206
18496
  ref: mountRef,
@@ -18212,7 +18502,7 @@ function XViewScene({
18212
18502
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
18213
18503
  }
18214
18504
  },
18215
- userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react32.default.createElement(
18505
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react31.default.createElement(
18216
18506
  XViewSidebar,
18217
18507
  {
18218
18508
  dbNodes: searchableDbNodes,
@@ -18224,7 +18514,7 @@ function XViewScene({
18224
18514
  importSuccessMessage,
18225
18515
  onActivateTimeline: handleActivateTimeline,
18226
18516
  onActivateQuestLens: handleActivateQuestLens,
18227
- onOpenAncestryBoard: handleOpenAncestryBoard,
18517
+ onOpenBoards: handleOpenBoards,
18228
18518
  viewType: viewParams == null ? void 0 : viewParams.type,
18229
18519
  viewName: viewParams == null ? void 0 : viewParams.name,
18230
18520
  onNavigateBack: handleNavigateBack,
@@ -18232,11 +18522,11 @@ function XViewScene({
18232
18522
  onToggle: setIsSidebarOpen,
18233
18523
  userRole: userPermissionRole,
18234
18524
  viewMembers,
18235
- milestones: ((_d = sceneDataRef.current) == null ? void 0 : _d.milestones) || [],
18525
+ milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
18236
18526
  onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
18237
18527
  }
18238
18528
  ),
18239
- creationMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
18529
+ creationMode.isActive && /* @__PURE__ */ import_react31.default.createElement(
18240
18530
  InSceneCreationForm,
18241
18531
  {
18242
18532
  onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
@@ -18257,8 +18547,8 @@ function XViewScene({
18257
18547
  },
18258
18548
  refEl: formRef,
18259
18549
  existingTypes: existingNodeTypes,
18260
- initialColor: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.color,
18261
- sourceTypes: (_f = creationMode.sourceNodeData) == null ? void 0 : _f.type,
18550
+ initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
18551
+ sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
18262
18552
  onIntensityChange: handleGhostNodeIntensityChange,
18263
18553
  onUploadFile: upload_file_action,
18264
18554
  availableDatasets,
@@ -18268,7 +18558,7 @@ function XViewScene({
18268
18558
  availableAncestries: allAvailableAncestries
18269
18559
  }
18270
18560
  ),
18271
- versionMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
18561
+ versionMode.isActive && /* @__PURE__ */ import_react31.default.createElement(
18272
18562
  InSceneVersionForm,
18273
18563
  {
18274
18564
  onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
@@ -18287,14 +18577,14 @@ function XViewScene({
18287
18577
  transition: "opacity 200ms ease-out"
18288
18578
  },
18289
18579
  refEl: formRef,
18290
- fixedType: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.type,
18291
- fixedColor: (_h = versionMode.sourceNodeData) == null ? void 0 : _h.color,
18580
+ fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
18581
+ fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
18292
18582
  onUploadFile: upload_file_action,
18293
18583
  availableNodes: allAvailableNodes,
18294
18584
  availableAncestries: allAvailableAncestries
18295
18585
  }
18296
18586
  ),
18297
- questMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
18587
+ questMode.isActive && /* @__PURE__ */ import_react31.default.createElement(
18298
18588
  InSceneQuestForm,
18299
18589
  {
18300
18590
  onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
@@ -18316,13 +18606,13 @@ function XViewScene({
18316
18606
  availableNodes: allAvailableNodes,
18317
18607
  availableAncestries: allAvailableAncestries,
18318
18608
  viewName: viewParams == null ? void 0 : viewParams.name,
18319
- questCounter: ((_i = sceneDataRef.current) == null ? void 0 : _i.quest_counter) || 1,
18609
+ questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
18320
18610
  viewMembers,
18321
- milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18611
+ milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
18322
18612
  onUpdateMilestones: handleUpdateMilestones
18323
18613
  }
18324
18614
  ),
18325
- readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react32.default.createElement(
18615
+ readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react31.default.createElement(
18326
18616
  "div",
18327
18617
  {
18328
18618
  className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isReadModeResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
@@ -18335,7 +18625,7 @@ function XViewScene({
18335
18625
  maxWidth: "92vw"
18336
18626
  }
18337
18627
  },
18338
- /* @__PURE__ */ import_react32.default.createElement(
18628
+ /* @__PURE__ */ import_react31.default.createElement(
18339
18629
  "div",
18340
18630
  {
18341
18631
  onPointerDown: (e) => {
@@ -18346,7 +18636,7 @@ function XViewScene({
18346
18636
  title: "Arraste para redimensionar"
18347
18637
  }
18348
18638
  ),
18349
- /* @__PURE__ */ import_react32.default.createElement(
18639
+ /* @__PURE__ */ import_react31.default.createElement(
18350
18640
  DescriptionReadModePanel,
18351
18641
  {
18352
18642
  key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
@@ -18381,7 +18671,7 @@ function XViewScene({
18381
18671
  }
18382
18672
  )
18383
18673
  ),
18384
- ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ import_react32.default.createElement(
18674
+ ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ import_react31.default.createElement(
18385
18675
  CreateAncestryPanel,
18386
18676
  {
18387
18677
  ancestryMode,
@@ -18417,7 +18707,7 @@ function XViewScene({
18417
18707
  onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
18418
18708
  }
18419
18709
  ),
18420
- editingAncestryRel.visible && /* @__PURE__ */ import_react32.default.createElement(
18710
+ editingAncestryRel.visible && /* @__PURE__ */ import_react31.default.createElement(
18421
18711
  AncestryRelationshipPanel,
18422
18712
  {
18423
18713
  data: editingAncestryRel.data,
@@ -18431,7 +18721,7 @@ function XViewScene({
18431
18721
  onUploadFile: upload_file_action
18432
18722
  }
18433
18723
  ),
18434
- detailsNode && detailsNode.is_quest && /* @__PURE__ */ import_react32.default.createElement(
18724
+ detailsNode && detailsNode.is_quest && /* @__PURE__ */ import_react31.default.createElement(
18435
18725
  QuestDetailsPanel,
18436
18726
  {
18437
18727
  node: detailsNode,
@@ -18453,11 +18743,11 @@ function XViewScene({
18453
18743
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
18454
18744
  viewMembers,
18455
18745
  currentUser: session == null ? void 0 : session.user,
18456
- milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18746
+ milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18457
18747
  onUpdateMilestones: handleUpdateMilestones
18458
18748
  }
18459
18749
  ),
18460
- detailsNode && !detailsNode.is_quest && /* @__PURE__ */ import_react32.default.createElement(
18750
+ detailsNode && !detailsNode.is_quest && /* @__PURE__ */ import_react31.default.createElement(
18461
18751
  NodeDetailsPanel,
18462
18752
  {
18463
18753
  node: detailsNode,
@@ -18489,7 +18779,7 @@ function XViewScene({
18489
18779
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
18490
18780
  }
18491
18781
  ),
18492
- detailsLink && /* @__PURE__ */ import_react32.default.createElement(
18782
+ detailsLink && /* @__PURE__ */ import_react31.default.createElement(
18493
18783
  RelationshipDetailsPanel,
18494
18784
  {
18495
18785
  link: detailsLink,
@@ -18503,7 +18793,7 @@ function XViewScene({
18503
18793
  userRole: userPermissionRole
18504
18794
  }
18505
18795
  ),
18506
- ancestryLinkDetails && /* @__PURE__ */ import_react32.default.createElement(
18796
+ ancestryLinkDetails && /* @__PURE__ */ import_react31.default.createElement(
18507
18797
  AncestryLinkDetailsPanel,
18508
18798
  {
18509
18799
  data: ancestryLinkDetails,
@@ -18514,7 +18804,7 @@ function XViewScene({
18514
18804
  onUploadFile: upload_file_action
18515
18805
  }
18516
18806
  ),
18517
- /* @__PURE__ */ import_react32.default.createElement(
18807
+ /* @__PURE__ */ import_react31.default.createElement(
18518
18808
  "div",
18519
18809
  {
18520
18810
  ref: tooltipRef,
@@ -18541,7 +18831,7 @@ function XViewScene({
18541
18831
  }
18542
18832
  }
18543
18833
  ),
18544
- /* @__PURE__ */ import_react32.default.createElement(
18834
+ /* @__PURE__ */ import_react31.default.createElement(
18545
18835
  ContextMenu,
18546
18836
  {
18547
18837
  data: contextMenu,
@@ -18574,7 +18864,7 @@ function XViewScene({
18574
18864
  onFinishQuest: handleFinishQuestQuick
18575
18865
  }
18576
18866
  ),
18577
- /* @__PURE__ */ import_react32.default.createElement(
18867
+ /* @__PURE__ */ import_react31.default.createElement(
18578
18868
  MultiNodeContextMenu,
18579
18869
  {
18580
18870
  data: multiContextMenu,
@@ -18594,7 +18884,7 @@ function XViewScene({
18594
18884
  )
18595
18885
  }
18596
18886
  ),
18597
- /* @__PURE__ */ import_react32.default.createElement(
18887
+ /* @__PURE__ */ import_react31.default.createElement(
18598
18888
  RelationshipContextMenu,
18599
18889
  {
18600
18890
  data: relationshipMenu,
@@ -18612,49 +18902,49 @@ function XViewScene({
18612
18902
  onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
18613
18903
  }
18614
18904
  ),
18615
- /* @__PURE__ */ import_react32.default.createElement(
18905
+ /* @__PURE__ */ import_react31.default.createElement(
18616
18906
  ImageViewer,
18617
18907
  {
18618
18908
  data: imageViewer,
18619
18909
  onClose: () => setImageViewer({ ...imageViewer, visible: false })
18620
18910
  }
18621
18911
  ),
18622
- /* @__PURE__ */ import_react32.default.createElement(
18623
- AncestryBoard,
18912
+ /* @__PURE__ */ import_react31.default.createElement(
18913
+ Boards,
18624
18914
  {
18625
- isOpen: isAncestryBoardOpen,
18626
- onClose: () => setIsAncestryBoardOpen(false),
18915
+ isOpen: isBoardsOpen,
18916
+ onClose: () => setIsBoardsOpen(false),
18627
18917
  onSelect: handleSelectAncestryFromBoard,
18628
18918
  availableAncestries: allAvailableAncestries,
18629
18919
  availableNodes: allAvailableNodes,
18630
- initialGroups: ancestryBoardData,
18631
- onSave: handleSaveAncestryBoard,
18920
+ initialBoardItems: boardItems,
18921
+ onSave: handleSaveBoards,
18632
18922
  userRole: userPermissionRole
18633
18923
  }
18634
18924
  ),
18635
- /* @__PURE__ */ import_react32.default.createElement(
18925
+ /* @__PURE__ */ import_react31.default.createElement(
18636
18926
  MilestoneManager,
18637
18927
  {
18638
18928
  isOpen: isMilestoneManagerOpen,
18639
18929
  onClose: () => setIsMilestoneManagerOpen(false),
18640
- milestones: ((_l = sceneDataRef.current) == null ? void 0 : _l.milestones) || [],
18930
+ milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18641
18931
  onUpdateMilestones: handleUpdateMilestones
18642
18932
  }
18643
18933
  ),
18644
- /* @__PURE__ */ import_react32.default.createElement(
18934
+ /* @__PURE__ */ import_react31.default.createElement(
18645
18935
  ImportParentFileModal,
18646
18936
  {
18647
18937
  isOpen: isImportModalOpen,
18648
18938
  onClose: () => setIsImportModalOpen(false),
18649
18939
  onConfirm: handleConfirmImport,
18650
18940
  session,
18651
- parentDbs: ((_m = sceneDataRef.current) == null ? void 0 : _m.parent_dbs) || [],
18941
+ parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
18652
18942
  onFetchAvailableFiles: import_parent_file_modal_get,
18653
18943
  currentViewName: viewParams == null ? void 0 : viewParams.name,
18654
18944
  currentAncestries: ancestryDataRef.current || []
18655
18945
  }
18656
18946
  ),
18657
- invalidTargetError && /* @__PURE__ */ import_react32.default.createElement(
18947
+ invalidTargetError && /* @__PURE__ */ import_react31.default.createElement(
18658
18948
  "div",
18659
18949
  {
18660
18950
  className: "ui-overlay",
@@ -18679,13 +18969,13 @@ function XViewScene({
18679
18969
  animation: "fadeInDown 0.5s cubic-bezier(0.16, 1, 0.3, 1)"
18680
18970
  }
18681
18971
  },
18682
- /* @__PURE__ */ import_react32.default.createElement("style", null, `
18972
+ /* @__PURE__ */ import_react31.default.createElement("style", null, `
18683
18973
  @keyframes fadeInDown {
18684
18974
  from { opacity: 0; transform: translate(-50%, -20px); }
18685
18975
  to { opacity: 1; transform: translate(-50%, 0); }
18686
18976
  }
18687
18977
  `),
18688
- /* @__PURE__ */ import_react32.default.createElement(
18978
+ /* @__PURE__ */ import_react31.default.createElement(
18689
18979
  "svg",
18690
18980
  {
18691
18981
  width: "20",
@@ -18697,12 +18987,12 @@ function XViewScene({
18697
18987
  strokeLinecap: "round",
18698
18988
  strokeLinejoin: "round"
18699
18989
  },
18700
- /* @__PURE__ */ import_react32.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
18701
- /* @__PURE__ */ import_react32.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
18702
- /* @__PURE__ */ import_react32.default.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
18990
+ /* @__PURE__ */ import_react31.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
18991
+ /* @__PURE__ */ import_react31.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
18992
+ /* @__PURE__ */ import_react31.default.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
18703
18993
  ),
18704
- /* @__PURE__ */ import_react32.default.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
18705
- /* @__PURE__ */ import_react32.default.createElement(
18994
+ /* @__PURE__ */ import_react31.default.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
18995
+ /* @__PURE__ */ import_react31.default.createElement(
18706
18996
  "button",
18707
18997
  {
18708
18998
  onClick: () => setInvalidTargetError(null),
@@ -18732,7 +19022,451 @@ function XViewScene({
18732
19022
  )
18733
19023
  );
18734
19024
  }
19025
+
19026
+ // src/x_view_server_logic.js
19027
+ async function save_view_data_logic(db_services, filename, data) {
19028
+ try {
19029
+ const saveResult = await db_services.save_file(filename, data);
19030
+ return saveResult;
19031
+ } catch (error) {
19032
+ console.error("catch (error) em save_view_data_logic:", error);
19033
+ return { success: false, error: error.message };
19034
+ }
19035
+ }
19036
+ async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
19037
+ var _a, _b;
19038
+ try {
19039
+ if (!session || !session.user) {
19040
+ return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
19041
+ }
19042
+ const membershipCheck = await db_services.check_membership(owner_id, type, scene_config, session.user.id);
19043
+ const isFullMember = membershipCheck.success && membershipCheck.isValidMember;
19044
+ if (!isFullMember && !focusNodeId && !focusAncestryId) {
19045
+ return { success: false, error: "Acesso Negado: Voc\xEA n\xE3o possui permiss\xE3o para acessar este cen\xE1rio." };
19046
+ }
19047
+ const sceneResponse = await db_services.get_file(`x_view_scenes/${owner_id}/${scene_config}`);
19048
+ if (!sceneResponse || !sceneResponse.success) {
19049
+ console.error("Falha ao buscar dados da cena:", sceneResponse == null ? void 0 : sceneResponse.error);
19050
+ return { success: false, error: `N\xE3o foi poss\xEDvel carregar o arquivo da cena: ${scene_config}` };
19051
+ }
19052
+ const sceneData = sceneResponse.data;
19053
+ const parentDbObjects = sceneData.parent_dbs || [];
19054
+ if (type && type.toLowerCase().includes("database")) {
19055
+ const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
19056
+ if (!selfExists) {
19057
+ parentDbObjects.push({ db_id: scene_config, owner_id });
19058
+ }
19059
+ }
19060
+ const parentResponsesPromises = parentDbObjects.map(
19061
+ (db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
19062
+ );
19063
+ const parentResponsesResults = await Promise.allSettled(parentResponsesPromises);
19064
+ const parentData = {};
19065
+ for (let i = 0; i < parentResponsesResults.length; i++) {
19066
+ const result = parentResponsesResults[i];
19067
+ const db_info = parentDbObjects[i];
19068
+ if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
19069
+ parentData[db_info.db_id] = result.value.data;
19070
+ } else {
19071
+ console.warn(
19072
+ `Arquivo pai n\xE3o carregado: ${db_info.db_id}. Pode ter sido deletado.`,
19073
+ result.status === "rejected" ? result.reason : (_b = result.value) == null ? void 0 : _b.error
19074
+ );
19075
+ }
19076
+ }
19077
+ if (type && type.toLowerCase() === "view") {
19078
+ parentData[scene_config] = {
19079
+ dataset_name: "Quests Internas (View)",
19080
+ nodes: sceneData.quest_nodes || [],
19081
+ links: sceneData.quest_links || []
19082
+ };
19083
+ }
19084
+ const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
19085
+ const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
19086
+ const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
19087
+ const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
19088
+ const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
19089
+ var _a2, _b2;
19090
+ const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
19091
+ if (nodeTypes.includes("quest")) {
19092
+ const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
19093
+ if (dbQuestNode) {
19094
+ return { ...sceneNode, ...dbQuestNode };
19095
+ }
19096
+ return sceneNode;
19097
+ }
19098
+ const dbNode = parentNodeMap.get(String(sceneNode.id));
19099
+ if (dbNode) {
19100
+ return { ...sceneNode, ...dbNode };
19101
+ }
19102
+ return null;
19103
+ }).filter(Boolean);
19104
+ const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
19105
+ const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
19106
+ const linkExistsInParent = parentLinkMap.has(`${sceneLink.source}-${sceneLink.target}`);
19107
+ const nodesAreValidForScene = validNodeIdsInScene.has(String(sceneLink.source)) && validNodeIdsInScene.has(String(sceneLink.target));
19108
+ return linkExistsInParent && nodesAreValidForScene;
19109
+ }).map((sceneLink) => parentLinkMap.get(`${sceneLink.source}-${sceneLink.target}`));
19110
+ const validatedSceneData = {
19111
+ ...sceneData,
19112
+ nodes: validatedNodes,
19113
+ links: validatedLinks
19114
+ };
19115
+ const ancestryFilePaths = [];
19116
+ ancestryFilePaths.push({
19117
+ path: `x_view_ancestry/${owner_id}/${scene_config}`,
19118
+ source_id: scene_config,
19119
+ owner_id,
19120
+ isSceneFile: true
19121
+ });
19122
+ parentDbObjects.forEach((db_info) => {
19123
+ ancestryFilePaths.push({
19124
+ path: `x_view_ancestry/${db_info.owner_id}/${db_info.db_id}`,
19125
+ source_id: db_info.db_id,
19126
+ owner_id: db_info.owner_id,
19127
+ isSceneFile: false
19128
+ });
19129
+ });
19130
+ const ancestryPromises = ancestryFilePaths.map((file) => db_services.get_file(file.path));
19131
+ const ancestryResults = await Promise.allSettled(ancestryPromises);
19132
+ const ancestriesFromSceneFile = [];
19133
+ const ancestriesFromDbFiles = [];
19134
+ ancestryResults.forEach((result, index) => {
19135
+ var _a2;
19136
+ const fileInfo = ancestryFilePaths[index];
19137
+ if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
19138
+ const ancestriesFromFile = result.value.data.map((ancestry) => {
19139
+ const existingSource = ancestry._source_file_id;
19140
+ const existingOwner = ancestry._source_owner_id;
19141
+ const isImportedItem = existingSource && existingSource !== fileInfo.source_id;
19142
+ return {
19143
+ ...ancestry,
19144
+ _source_file_id: isImportedItem ? existingSource : fileInfo.source_id,
19145
+ _source_owner_id: isImportedItem ? existingOwner : fileInfo.owner_id
19146
+ };
19147
+ });
19148
+ if (fileInfo.isSceneFile) {
19149
+ ancestriesFromSceneFile.push(...ancestriesFromFile);
19150
+ } else {
19151
+ ancestriesFromDbFiles.push(...ancestriesFromFile);
19152
+ }
19153
+ }
19154
+ });
19155
+ const ancestryMap = /* @__PURE__ */ new Map();
19156
+ ancestriesFromDbFiles.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
19157
+ ancestriesFromSceneFile.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
19158
+ let ancestryData = Array.from(ancestryMap.values());
19159
+ const externalSourcesToRefresh = /* @__PURE__ */ new Map();
19160
+ ancestryData.forEach((anc) => {
19161
+ const targetSourceId = anc._source_file_id || anc._imported_from_view_id;
19162
+ const targetOwnerId = anc._source_owner_id || anc._imported_from_view_owner_id;
19163
+ if (targetSourceId && targetSourceId !== scene_config && targetOwnerId) {
19164
+ const isAlreadyLoadedAsParent = parentDbObjects.some((db) => String(db.db_id) === String(targetSourceId));
19165
+ if (!isAlreadyLoadedAsParent) {
19166
+ const key = `${targetOwnerId}/${targetSourceId}`;
19167
+ externalSourcesToRefresh.set(key, {
19168
+ owner_id: targetOwnerId,
19169
+ source_id: targetSourceId,
19170
+ key
19171
+ });
19172
+ }
19173
+ }
19174
+ });
19175
+ const successfullyFetchedSources = /* @__PURE__ */ new Set();
19176
+ const failedSources = /* @__PURE__ */ new Set();
19177
+ if (externalSourcesToRefresh.size > 0) {
19178
+ const refreshPromises = Array.from(externalSourcesToRefresh.values()).map(
19179
+ (src) => db_services.get_file(`x_view_ancestry/${src.owner_id}/${src.source_id}`).then((res) => ({ ...res, _meta_key: src.key }))
19180
+ );
19181
+ const refreshResults = await Promise.allSettled(refreshPromises);
19182
+ const freshAncestryMap = /* @__PURE__ */ new Map();
19183
+ refreshResults.forEach((result) => {
19184
+ var _a2, _b2;
19185
+ if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
19186
+ successfullyFetchedSources.add(result.value._meta_key);
19187
+ result.value.data.forEach((freshAnc) => {
19188
+ if (!freshAnc.is_private) {
19189
+ freshAncestryMap.set(String(freshAnc.ancestry_id), freshAnc);
19190
+ }
19191
+ });
19192
+ } else if (result.status === "fulfilled" && !((_b2 = result.value) == null ? void 0 : _b2.success)) {
19193
+ failedSources.add(result.value._meta_key);
19194
+ }
19195
+ });
19196
+ ancestryData = ancestryData.filter((localAnc) => {
19197
+ const targetSourceId = localAnc._source_file_id || localAnc._imported_from_view_id;
19198
+ const targetOwnerId = localAnc._source_owner_id || localAnc._imported_from_view_owner_id;
19199
+ if (!targetSourceId || targetSourceId === scene_config) return true;
19200
+ const key = `${targetOwnerId}/${targetSourceId}`;
19201
+ if (failedSources.has(key)) {
19202
+ return false;
19203
+ }
19204
+ if (externalSourcesToRefresh.has(key) && successfullyFetchedSources.has(key)) {
19205
+ const stillExists = freshAncestryMap.has(String(localAnc.ancestry_id));
19206
+ return stillExists;
19207
+ }
19208
+ return true;
19209
+ }).map((localAnc) => {
19210
+ const freshVersion = freshAncestryMap.get(String(localAnc.ancestry_id));
19211
+ if (freshVersion) {
19212
+ return {
19213
+ ...freshVersion,
19214
+ _imported_from_view_id: localAnc._imported_from_view_id,
19215
+ _imported_from_view_owner_id: localAnc._imported_from_view_owner_id,
19216
+ _origin_db_ids: localAnc._origin_db_ids,
19217
+ _source_file_id: localAnc._source_file_id,
19218
+ _source_owner_id: localAnc._source_owner_id
19219
+ };
19220
+ }
19221
+ return localAnc;
19222
+ });
19223
+ }
19224
+ const ancestryFilePath = `x_view_ancestry/${owner_id}/${scene_config}`;
19225
+ const parentNodeIds = new Set(allNodes.map((node) => String(node.id)));
19226
+ const pruneTree = (node) => {
19227
+ if (!node) return null;
19228
+ if (node.is_section) {
19229
+ const validChildren2 = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
19230
+ return { ...node, children: validChildren2 };
19231
+ }
19232
+ if (!parentNodeIds.has(String(node.node_id))) {
19233
+ return null;
19234
+ }
19235
+ const validChildren = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
19236
+ let validBranches = [];
19237
+ if (node.parallel_branches) {
19238
+ validBranches = node.parallel_branches.map((branch) => ({
19239
+ ...branch,
19240
+ tree: pruneTree(branch.tree)
19241
+ })).filter((b) => b.tree !== null);
19242
+ }
19243
+ return {
19244
+ ...node,
19245
+ children: validChildren,
19246
+ parallel_branches: validBranches
19247
+ };
19248
+ };
19249
+ const originalAncestryDataString = JSON.stringify(Array.from(ancestryMap.values()));
19250
+ const cleanedAncestryData = ancestryData.map((ancestry) => {
19251
+ if (!parentNodeIds.has(String(ancestry.ancestral_node))) return null;
19252
+ const cleanedTree = pruneTree(ancestry.tree);
19253
+ if (!cleanedTree) return null;
19254
+ let cleanedAbstraction = null;
19255
+ if (ancestry.abstraction_tree) {
19256
+ cleanedAbstraction = pruneTree(ancestry.abstraction_tree);
19257
+ }
19258
+ return {
19259
+ ...ancestry,
19260
+ tree: cleanedTree,
19261
+ abstraction_tree: cleanedAbstraction
19262
+ };
19263
+ }).filter(Boolean);
19264
+ if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
19265
+ ancestryData = cleanedAncestryData;
19266
+ try {
19267
+ await db_services.save_file(ancestryFilePath, ancestryData);
19268
+ } catch (saveError) {
19269
+ console.error("Falha ao salvar o arquivo de ancestralidade da cena atualizado:", saveError);
19270
+ }
19271
+ }
19272
+ if (!isFullMember) {
19273
+ const requiredNodeIds = /* @__PURE__ */ new Set();
19274
+ const requiredAncestryIds = /* @__PURE__ */ new Set();
19275
+ if (focusNodeId) requiredNodeIds.add(String(focusNodeId));
19276
+ if (focusAncestryId) requiredAncestryIds.add(String(focusAncestryId));
19277
+ const allNodesFromDb = Object.values(parentData).flatMap((db) => db.nodes || []);
19278
+ const extractDependenciesFromText = (text) => {
19279
+ if (!text) return;
19280
+ const mentionRegex = /\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g;
19281
+ const refRegex = /\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g;
19282
+ let match;
19283
+ while ((match = mentionRegex.exec(text)) !== null) {
19284
+ requiredNodeIds.add(match[1]);
19285
+ }
19286
+ while ((match = refRegex.exec(text)) !== null) {
19287
+ if (match[1] === "node") requiredNodeIds.add(match[2]);
19288
+ if (match[1] === "ancestry") requiredAncestryIds.add(match[2]);
19289
+ }
19290
+ };
19291
+ const extractTreeDependencies = (treeItem) => {
19292
+ var _a2;
19293
+ if (!treeItem) return;
19294
+ if (treeItem.node_id) requiredNodeIds.add(String(treeItem.node_id));
19295
+ if ((_a2 = treeItem.node) == null ? void 0 : _a2.id) requiredNodeIds.add(String(treeItem.node.id));
19296
+ if (treeItem.children) {
19297
+ treeItem.children.forEach(extractTreeDependencies);
19298
+ }
19299
+ if (treeItem.parallel_branches) {
19300
+ treeItem.parallel_branches.forEach((branch) => {
19301
+ if (branch.linked_ancestry_id) {
19302
+ requiredAncestryIds.add(String(branch.linked_ancestry_id));
19303
+ }
19304
+ if (branch.description) extractDependenciesFromText(branch.description);
19305
+ if (branch.description_sections) {
19306
+ branch.description_sections.forEach((s) => extractDependenciesFromText(s.content));
19307
+ }
19308
+ extractTreeDependencies(branch.tree);
19309
+ });
19310
+ }
19311
+ };
19312
+ let previousSize;
19313
+ do {
19314
+ previousSize = requiredNodeIds.size + requiredAncestryIds.size;
19315
+ requiredAncestryIds.forEach((ancId) => {
19316
+ const anc = ancestryData.find((a) => String(a.ancestry_id) === ancId);
19317
+ if (anc && !anc.is_private) {
19318
+ if (anc.description) extractDependenciesFromText(anc.description);
19319
+ if (anc.description_sections) {
19320
+ anc.description_sections.forEach((s) => extractDependenciesFromText(s.content));
19321
+ }
19322
+ extractTreeDependencies(anc.tree);
19323
+ extractTreeDependencies(anc.abstraction_tree);
19324
+ }
19325
+ });
19326
+ requiredNodeIds.forEach((nodeId) => {
19327
+ const node = allNodesFromDb.find((n) => String(n.id) === nodeId);
19328
+ if (node) {
19329
+ if (node.description) extractDependenciesFromText(node.description);
19330
+ if (node.description_sections) {
19331
+ node.description_sections.forEach((s) => extractDependenciesFromText(s.content));
19332
+ }
19333
+ }
19334
+ });
19335
+ } while (requiredNodeIds.size + requiredAncestryIds.size > previousSize);
19336
+ const restrictedSceneData = { ...validatedSceneData, nodes: [], links: [] };
19337
+ const restrictedParentData = {};
19338
+ const restrictedAncestryData = ancestryData.filter((a) => requiredAncestryIds.has(String(a.ancestry_id)) && !a.is_private);
19339
+ for (const [dbId, dbContent] of Object.entries(parentData)) {
19340
+ const filteredNodes = (dbContent.nodes || []).filter((n) => requiredNodeIds.has(String(n.id)));
19341
+ if (filteredNodes.length > 0) {
19342
+ restrictedParentData[dbId] = { ...dbContent, nodes: filteredNodes, links: [] };
19343
+ }
19344
+ }
19345
+ if (focusNodeId) {
19346
+ const mainNode = allNodesFromDb.find((n) => String(n.id) === String(focusNodeId));
19347
+ if (mainNode) {
19348
+ restrictedSceneData.nodes = [mainNode];
19349
+ }
19350
+ }
19351
+ return {
19352
+ success: true,
19353
+ data: {
19354
+ scene: restrictedSceneData,
19355
+ parent: restrictedParentData,
19356
+ ancestry: restrictedAncestryData
19357
+ }
19358
+ };
19359
+ }
19360
+ return {
19361
+ success: true,
19362
+ data: { scene: validatedSceneData, parent: parentData, ancestry: ancestryData }
19363
+ };
19364
+ } catch (error) {
19365
+ console.error("Erro em get_scene_view_data_logic:", error);
19366
+ return { success: false, error: error.message };
19367
+ }
19368
+ }
19369
+ async function import_parent_file_modal_get_logic(db_services, session) {
19370
+ try {
19371
+ const call_firestore_get_x_view_data = await db_services.get_firestore_data(session);
19372
+ const x_view_databases = call_firestore_get_x_view_data.data.sub_collections.x_view_databases || [];
19373
+ const x_views = call_firestore_get_x_view_data.data.sub_collections.x_views || [];
19374
+ return {
19375
+ success: true,
19376
+ data: {
19377
+ databases: x_view_databases,
19378
+ views: x_views
19379
+ }
19380
+ };
19381
+ } catch (error) {
19382
+ console.error("catch (error) em import_parent_file_modal_get_logic:", error);
19383
+ return { success: false, error: error.message };
19384
+ }
19385
+ }
19386
+ async function get_single_parent_file_logic(db_services, file_id, session) {
19387
+ try {
19388
+ const call_GCP_cloud_storage_get_file = await db_services.get_file(`x_view_dbs/${session.user.id}/${file_id}`);
19389
+ return call_GCP_cloud_storage_get_file;
19390
+ } catch (error) {
19391
+ console.error("catch (error) em get_single_parent_file_logic:", error);
19392
+ return { success: false, error: error.message };
19393
+ }
19394
+ }
19395
+ async function x_view_add_new_parent_file_to_scene_at_firebase(file_id, session, new_parent, db_services) {
19396
+ try {
19397
+ const update_data = {
19398
+ scene_id: file_id,
19399
+ new_parent,
19400
+ session
19401
+ };
19402
+ const call_firestore_add_new_parent_file_to_scene_at_firebase = await db_services.add_new_parent_file_to_scene_at_firebase(update_data);
19403
+ return call_firestore_add_new_parent_file_to_scene_at_firebase;
19404
+ } catch (error) {
19405
+ console.error("catch (error) em get_single_parent_file_logic:", error);
19406
+ return { success: false, error: error.message };
19407
+ }
19408
+ }
19409
+ async function get_ancestry_file_logic(db_services, file_id, owner_id) {
19410
+ try {
19411
+ const path = `x_view_ancestry/${owner_id}/${file_id}`;
19412
+ const call_GCP_cloud_storage_get_file = await db_services.get_file(path);
19413
+ return call_GCP_cloud_storage_get_file;
19414
+ } catch (error) {
19415
+ console.error("catch (error) em get_ancestry_file_logic:", error);
19416
+ return { success: false, error: error.message };
19417
+ }
19418
+ }
19419
+ async function save_boards_logic(db_services, scene_id, type, boardItems, session, owner_id) {
19420
+ try {
19421
+ const targetOwnerId = owner_id || session.user.id;
19422
+ return await db_services.save_boards(session, scene_id, type, boardItems, targetOwnerId);
19423
+ } catch (error) {
19424
+ console.error("Erro em save_boards_logic:", error);
19425
+ return { success: false, error: error.message };
19426
+ }
19427
+ }
19428
+ async function get_boards_logic(db_services, scene_id, type, session, owner_id) {
19429
+ try {
19430
+ const targetOwnerId = owner_id || session.user.id;
19431
+ return await db_services.get_boards(session, scene_id, type, targetOwnerId);
19432
+ } catch (error) {
19433
+ console.error("Erro em get_boards_logic:", error);
19434
+ return { success: false, error: error.message };
19435
+ }
19436
+ }
19437
+ async function delete_uploaded_file_logic(db_services, fileUrl) {
19438
+ try {
19439
+ if (db_services.delete_public_file) {
19440
+ return await db_services.delete_public_file(fileUrl);
19441
+ }
19442
+ return { success: false, error: "Servi\xE7o de dele\xE7\xE3o n\xE3o configurado." };
19443
+ } catch (error) {
19444
+ console.error("Erro em delete_uploaded_file_logic:", error);
19445
+ return { success: false, error: error.message };
19446
+ }
19447
+ }
19448
+ async function get_view_members_logic(db_services, ownerId, type, itemId) {
19449
+ try {
19450
+ if (!db_services.get_view_members) {
19451
+ return { success: false, error: "Servi\xE7o de busca de membros n\xE3o configurado." };
19452
+ }
19453
+ return await db_services.get_view_members(ownerId, type, itemId);
19454
+ } catch (error) {
19455
+ console.error("Erro em get_view_members_logic:", error);
19456
+ return { success: false, error: error.message };
19457
+ }
19458
+ }
18735
19459
  // Annotate the CommonJS export names for ESM import in node:
18736
19460
  0 && (module.exports = {
18737
- XViewScene
19461
+ XViewScene,
19462
+ delete_uploaded_file_logic,
19463
+ get_ancestry_file_logic,
19464
+ get_boards_logic,
19465
+ get_scene_view_data_logic,
19466
+ get_single_parent_file_logic,
19467
+ get_view_members_logic,
19468
+ import_parent_file_modal_get_logic,
19469
+ save_boards_logic,
19470
+ save_view_data_logic,
19471
+ x_view_add_new_parent_file_to_scene_at_firebase
18738
19472
  });