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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -29,24 +30,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
30
  // src/index.js
30
31
  var index_exports = {};
31
32
  __export(index_exports, {
32
- XViewScene: () => XViewScene,
33
- delete_uploaded_file_logic: () => delete_uploaded_file_logic,
34
- get_ancestry_board_logic: () => get_ancestry_board_logic,
35
- get_ancestry_file_logic: () => get_ancestry_file_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_ancestry_board_logic: () => save_ancestry_board_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
33
+ XViewScene: () => XViewScene
43
34
  });
44
35
  module.exports = __toCommonJS(index_exports);
45
36
 
46
37
  // src/XViewScene.jsx
47
- var import_react29 = __toESM(require("react"));
38
+ var import_react32 = __toESM(require("react"));
48
39
  var import_navigation = require("next/navigation");
49
- var import_react30 = require("next-auth/react");
40
+ var import_react33 = require("next-auth/react");
50
41
  var import_crypto_js = __toESM(require("crypto-js"));
51
42
  var THREE3 = __toESM(require("three"));
52
43
  var import_OrbitControls = require("three/examples/jsm/controls/OrbitControls.js");
@@ -118,55 +109,7 @@ function defineAbilityFor(role) {
118
109
 
119
110
  // src/logic/x_view_utils.js
120
111
  var import_react = require("react");
121
-
122
- // node_modules/uuid/dist/esm-node/rng.js
123
- var import_crypto = __toESM(require("crypto"));
124
- var rnds8Pool = new Uint8Array(256);
125
- var poolPtr = rnds8Pool.length;
126
- function rng() {
127
- if (poolPtr > rnds8Pool.length - 16) {
128
- import_crypto.default.randomFillSync(rnds8Pool);
129
- poolPtr = 0;
130
- }
131
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
132
- }
133
-
134
- // node_modules/uuid/dist/esm-node/stringify.js
135
- var byteToHex = [];
136
- for (let i = 0; i < 256; ++i) {
137
- byteToHex.push((i + 256).toString(16).slice(1));
138
- }
139
- function unsafeStringify(arr, offset = 0) {
140
- return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
141
- }
142
-
143
- // node_modules/uuid/dist/esm-node/native.js
144
- var import_crypto2 = __toESM(require("crypto"));
145
- var native_default = {
146
- randomUUID: import_crypto2.default.randomUUID
147
- };
148
-
149
- // node_modules/uuid/dist/esm-node/v4.js
150
- function v4(options, buf, offset) {
151
- if (native_default.randomUUID && !buf && !options) {
152
- return native_default.randomUUID();
153
- }
154
- options = options || {};
155
- const rnds = options.random || (options.rng || rng)();
156
- rnds[6] = rnds[6] & 15 | 64;
157
- rnds[8] = rnds[8] & 63 | 128;
158
- if (buf) {
159
- offset = offset || 0;
160
- for (let i = 0; i < 16; ++i) {
161
- buf[offset + i] = rnds[i];
162
- }
163
- return buf;
164
- }
165
- return unsafeStringify(rnds);
166
- }
167
- var v4_default = v4;
168
-
169
- // src/logic/x_view_utils.js
112
+ var import_uuid = require("uuid");
170
113
  var THREE2 = __toESM(require("three"));
171
114
 
172
115
  // src/logic/x_view_config.js
@@ -2519,15 +2462,15 @@ function createNewCustomProperty(existingProps = []) {
2519
2462
  switch (nextType) {
2520
2463
  case "links":
2521
2464
  nextKey = "Links";
2522
- nextValue = [{ id: v4_default(), name: "", value: "" }];
2465
+ nextValue = [{ id: (0, import_uuid.v4)(), name: "", value: "" }];
2523
2466
  break;
2524
2467
  case "images":
2525
2468
  nextKey = "Images";
2526
- nextValue = [{ id: v4_default(), name: "1", value: "" }];
2469
+ nextValue = [{ id: (0, import_uuid.v4)(), name: "1", value: "" }];
2527
2470
  break;
2528
2471
  case "documents":
2529
2472
  nextKey = "Documents";
2530
- nextValue = [{ id: v4_default(), name: "1", value: "" }];
2473
+ nextValue = [{ id: (0, import_uuid.v4)(), name: "1", value: "" }];
2531
2474
  break;
2532
2475
  case "date":
2533
2476
  nextKey = "Date";
@@ -2537,14 +2480,14 @@ function createNewCustomProperty(existingProps = []) {
2537
2480
  nextValue = 0;
2538
2481
  break;
2539
2482
  case "list":
2540
- nextValue = [{ id: v4_default(), name: "", value: "" }];
2483
+ nextValue = [{ id: (0, import_uuid.v4)(), name: "", value: "" }];
2541
2484
  break;
2542
2485
  default:
2543
2486
  nextValue = "";
2544
2487
  break;
2545
2488
  }
2546
2489
  return {
2547
- id: v4_default(),
2490
+ id: (0, import_uuid.v4)(),
2548
2491
  key: nextKey,
2549
2492
  type: nextType,
2550
2493
  value: nextValue,
@@ -2789,7 +2732,7 @@ function extractCustomPropsFromNode(node) {
2789
2732
  if (val && typeof val === "object") {
2790
2733
  if ("date_interval" in val) {
2791
2734
  return {
2792
- id: v4_default(),
2735
+ id: (0, import_uuid.v4)(),
2793
2736
  key,
2794
2737
  type: "date",
2795
2738
  value: {
@@ -2801,7 +2744,7 @@ function extractCustomPropsFromNode(node) {
2801
2744
  }
2802
2745
  if ("year" in val) {
2803
2746
  return {
2804
- id: v4_default(),
2747
+ id: (0, import_uuid.v4)(),
2805
2748
  key,
2806
2749
  type: "date",
2807
2750
  value: { type: "Ano", value: val.year || "" }
@@ -2809,7 +2752,7 @@ function extractCustomPropsFromNode(node) {
2809
2752
  }
2810
2753
  if ("date" in val) {
2811
2754
  return {
2812
- id: v4_default(),
2755
+ id: (0, import_uuid.v4)(),
2813
2756
  key,
2814
2757
  type: "date",
2815
2758
  value: { type: "Data", value: val.date || "" }
@@ -2817,7 +2760,7 @@ function extractCustomPropsFromNode(node) {
2817
2760
  }
2818
2761
  }
2819
2762
  return {
2820
- id: v4_default(),
2763
+ id: (0, import_uuid.v4)(),
2821
2764
  key,
2822
2765
  type: "date",
2823
2766
  value: { type: "Data", value: "" }
@@ -2825,14 +2768,14 @@ function extractCustomPropsFromNode(node) {
2825
2768
  }
2826
2769
  if (t === "list" || t === "links" || t === "images" || t === "documents") {
2827
2770
  const safeList = (val || []).map((item) => ({
2828
- id: item.id || v4_default(),
2771
+ id: item.id || (0, import_uuid.v4)(),
2829
2772
  name: item.name ?? "",
2830
2773
  value: item.value ?? ""
2831
2774
  }));
2832
- return { id: v4_default(), key, type: t, value: safeList };
2775
+ return { id: (0, import_uuid.v4)(), key, type: t, value: safeList };
2833
2776
  }
2834
2777
  return {
2835
- id: v4_default(),
2778
+ id: (0, import_uuid.v4)(),
2836
2779
  key,
2837
2780
  type: t,
2838
2781
  value: t === "number" ? Number(val) || 0 : String(val ?? "")
@@ -3105,16 +3048,16 @@ var processDescriptionForSave = (text, existingSections = []) => {
3105
3048
  if (existingMatch) {
3106
3049
  finalUuid = existingMatch.id;
3107
3050
  } else {
3108
- finalUuid = v4_default();
3051
+ finalUuid = (0, import_uuid.v4)();
3109
3052
  }
3110
3053
  } else {
3111
3054
  finalUuid = numericMap.get(numStr);
3112
3055
  if (!finalUuid) {
3113
- finalUuid = v4_default();
3056
+ finalUuid = (0, import_uuid.v4)();
3114
3057
  }
3115
3058
  }
3116
3059
  if (usedIds.has(finalUuid)) {
3117
- finalUuid = v4_default();
3060
+ finalUuid = (0, import_uuid.v4)();
3118
3061
  }
3119
3062
  usedIds.add(finalUuid);
3120
3063
  processedSections.push({
@@ -3225,18 +3168,18 @@ function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
3225
3168
  function createTimelineEntry(actorId, description, type = "comment", extras = {}) {
3226
3169
  const { links = [], images = [], metadata = {} } = extras;
3227
3170
  return {
3228
- id: v4_default(),
3171
+ id: (0, import_uuid.v4)(),
3229
3172
  type,
3230
3173
  timestamp: Date.now(),
3231
3174
  actorId,
3232
3175
  description,
3233
3176
  links: links.map((l) => ({
3234
- id: l.id || v4_default(),
3177
+ id: l.id || (0, import_uuid.v4)(),
3235
3178
  name: l.name || "",
3236
3179
  value: l.value || ""
3237
3180
  })),
3238
3181
  images: images.map((img) => ({
3239
- id: img.id || v4_default(),
3182
+ id: img.id || (0, import_uuid.v4)(),
3240
3183
  name: img.name || "",
3241
3184
  value: img.value || ""
3242
3185
  }))
@@ -4463,6 +4406,7 @@ function XViewSidebar({
4463
4406
 
4464
4407
  // src/components/AncestryRelationshipPanel.jsx
4465
4408
  var import_react9 = __toESM(require("react"));
4409
+ var import_uuid3 = require("uuid");
4466
4410
 
4467
4411
  // src/components/CustomPropertyDisplay.jsx
4468
4412
  var import_react4 = __toESM(require("react"));
@@ -5222,6 +5166,7 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
5222
5166
  }
5223
5167
 
5224
5168
  // src/components/DescriptionEditModal.jsx
5169
+ var import_uuid2 = require("uuid");
5225
5170
  var getNextSectionNumber = (currentText) => {
5226
5171
  const regex = /\*\/\s*(\d+)(?::[a-zA-Z0-9-]+)?\s*\//g;
5227
5172
  let max = 0;
@@ -5353,7 +5298,7 @@ function DescriptionEditModal({
5353
5298
  const el = textareaRef.current;
5354
5299
  if (!el) return;
5355
5300
  const nextNum = getNextSectionNumber(text);
5356
- const uniqueSuffix = v4_default().slice(0, 4);
5301
+ const uniqueSuffix = (0, import_uuid2.v4)().slice(0, 4);
5357
5302
  insertAtCursor(`*/${nextNum}:${uniqueSuffix}/ `);
5358
5303
  };
5359
5304
  const handleImportSelect = (tags) => {
@@ -5364,7 +5309,7 @@ function DescriptionEditModal({
5364
5309
  let currentNum = getNextSectionNumber(currentText);
5365
5310
  let blockToInsert = "";
5366
5311
  tagsArray.forEach((tag) => {
5367
- const uniqueSuffix = v4_default().slice(0, 4);
5312
+ const uniqueSuffix = (0, import_uuid2.v4)().slice(0, 4);
5368
5313
  blockToInsert += `
5369
5314
  */${currentNum}:${uniqueSuffix}/ ${tag}
5370
5315
  `;
@@ -6693,6 +6638,7 @@ function AncestryRelationshipPanel({
6693
6638
  // src/components/CreateAncestryPanel.jsx
6694
6639
  var import_react11 = __toESM(require("react"));
6695
6640
  var import_fi10 = require("react-icons/fi");
6641
+ var import_uuid4 = require("uuid");
6696
6642
 
6697
6643
  // src/components/AncestryPickerModal.jsx
6698
6644
  var import_react10 = __toESM(require("react"));
@@ -7729,7 +7675,7 @@ function CreateAncestryPanel({
7729
7675
  const nodeData = availableNodes.find((n) => String(n.id) === String(nodeId));
7730
7676
  const dirSuffix = direction === "left" ? "(Esq)" : "(Dir)";
7731
7677
  branch = {
7732
- id: v4_default(),
7678
+ id: (0, import_uuid4.v4)(),
7733
7679
  name: `Ramifica\xE7\xE3o ${dirSuffix} de ${(nodeData == null ? void 0 : nodeData.name) || "Node"}`,
7734
7680
  description: "",
7735
7681
  description_sections: [],
@@ -8508,6 +8454,7 @@ function ImageViewer({ data, onClose }) {
8508
8454
 
8509
8455
  // src/components/InSceneCreationForm.jsx
8510
8456
  var import_react14 = __toESM(require("react"));
8457
+ var import_uuid5 = require("uuid");
8511
8458
 
8512
8459
  // src/components/ColorPicker.jsx
8513
8460
  var import_react13 = __toESM(require("react"));
@@ -9084,6 +9031,7 @@ function InSceneCreationForm({
9084
9031
 
9085
9032
  // src/components/InSceneVersionForm.jsx
9086
9033
  var import_react15 = __toESM(require("react"));
9034
+ var import_uuid6 = require("uuid");
9087
9035
  var import_fi14 = require("react-icons/fi");
9088
9036
  function InSceneVersionForm({
9089
9037
  onSave,
@@ -9106,7 +9054,7 @@ function InSceneVersionForm({
9106
9054
  const [description, setDescription] = (0, import_react15.useState)("");
9107
9055
  const [customProps, setCustomProps] = (0, import_react15.useState)([
9108
9056
  {
9109
- id: v4_default(),
9057
+ id: (0, import_uuid6.v4)(),
9110
9058
  key: "Date",
9111
9059
  type: "date",
9112
9060
  value: { type: "Data", value: "" },
@@ -9399,6 +9347,7 @@ function InSceneVersionForm({
9399
9347
 
9400
9348
  // src/components/InSceneQuestForm.jsx
9401
9349
  var import_react17 = __toESM(require("react"));
9350
+ var import_uuid7 = require("uuid");
9402
9351
  var import_fi16 = require("react-icons/fi");
9403
9352
 
9404
9353
  // src/components/QuestReviewStackEditor.jsx
@@ -10304,6 +10253,7 @@ function InSceneQuestForm({
10304
10253
 
10305
10254
  // src/components/NodeDetailsPanel.jsx
10306
10255
  var import_react18 = __toESM(require("react"));
10256
+ var import_uuid8 = require("uuid");
10307
10257
  var import_fi17 = require("react-icons/fi");
10308
10258
  function NodeDetailsPanel({
10309
10259
  node,
@@ -10818,6 +10768,7 @@ function NodeDetailsPanel({
10818
10768
 
10819
10769
  // src/components/QuestDetailsPanel.jsx
10820
10770
  var import_react20 = __toESM(require("react"));
10771
+ var import_uuid9 = require("uuid");
10821
10772
  var import_fi19 = require("react-icons/fi");
10822
10773
 
10823
10774
  // src/components/QuestTimeline.jsx
@@ -11256,7 +11207,7 @@ ${noteText}` : noteText : entry.notes,
11256
11207
  }, 100);
11257
11208
  };
11258
11209
  const addLinkToNote = () => {
11259
- setNoteLinks([...noteLinks, { id: v4_default(), name: "", value: "" }]);
11210
+ setNoteLinks([...noteLinks, { id: (0, import_uuid9.v4)(), name: "", value: "" }]);
11260
11211
  };
11261
11212
  const removeLinkFromNote = (id) => {
11262
11213
  setNoteLinks(noteLinks.filter((l) => l.id !== id));
@@ -11265,7 +11216,7 @@ ${noteText}` : noteText : entry.notes,
11265
11216
  setNoteLinks(noteLinks.map((l) => l.id === id ? { ...l, [field]: val } : l));
11266
11217
  };
11267
11218
  const addImageToNote = () => {
11268
- setNoteImages([...noteImages, { id: v4_default(), name: "Image", value: "" }]);
11219
+ setNoteImages([...noteImages, { id: (0, import_uuid9.v4)(), name: "Image", value: "" }]);
11269
11220
  };
11270
11221
  const removeImageFromNote = (id) => {
11271
11222
  setNoteImages(noteImages.filter((img) => img.id !== id));
@@ -12142,6 +12093,7 @@ function MultiNodeContextMenu({
12142
12093
 
12143
12094
  // src/components/RelationshipDetailsPanel.jsx
12144
12095
  var import_react22 = __toESM(require("react"));
12096
+ var import_uuid10 = require("uuid");
12145
12097
  var import_fi20 = require("react-icons/fi");
12146
12098
  function RelationshipDetailsPanel({
12147
12099
  link,
@@ -12951,149 +12903,371 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
12951
12903
  }
12952
12904
 
12953
12905
  // src/components/AncestryBoard.jsx
12906
+ var import_react30 = __toESM(require("react"));
12907
+ var import_fi23 = require("react-icons/fi");
12908
+ var import_uuid11 = require("uuid");
12909
+
12910
+ // src/components/MentionEditor.jsx
12911
+ 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
+
12917
+ // src/components/MentionList.jsx
12954
12918
  var import_react27 = __toESM(require("react"));
12955
12919
  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;
12953
+ }
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;
12994
+
12995
+ // src/components/MentionEditor.jsx
12996
+ var CustomMention = import_extension_mention.default.extend({
12997
+ addAttributes() {
12998
+ 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
+ };
13023
+ }
13024
+ }
13025
+ };
13026
+ }
13027
+ });
13028
+ var MentionEditor = ({
13029
+ initialValue = "",
13030
+ 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);
13138
+ }
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;
13206
+ }
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;
13211
+ }
13212
+
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
+ `));
13226
+ };
13227
+ var MentionEditor_default = MentionEditor;
13228
+
13229
+ // src/components/AncestryBoard.jsx
12956
13230
  var GroupItem = ({
12957
13231
  group,
12958
13232
  index,
12959
- siblings,
12960
13233
  onUpdate,
12961
13234
  onDelete,
12962
13235
  onAddSubgroup,
12963
13236
  onIndent,
12964
13237
  onOutdent,
12965
- onRemoveAncestry,
12966
- onRequestPickAncestry,
12967
- pickingGroupId,
12968
13238
  onPlayAncestry,
12969
- availableIds,
13239
+ availableMentionItems,
12970
13240
  canEdit
12971
13241
  }) => {
12972
13242
  const canIndent = index > 0;
12973
- const isPickingForThisGroup = pickingGroupId === group.id;
12974
- const textareaRef = (0, import_react27.useRef)(null);
12975
- const adjustHeight = () => {
12976
- const textarea = textareaRef.current;
12977
- if (textarea) {
12978
- textarea.style.height = "auto";
12979
- textarea.style.height = `${textarea.scrollHeight}px`;
12980
- }
12981
- };
12982
- (0, import_react27.useEffect)(() => {
12983
- adjustHeight();
12984
- }, [group.text]);
12985
- return /* @__PURE__ */ import_react27.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_react27.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react27.default.createElement(
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(
12986
13244
  "div",
12987
13245
  {
12988
- className: `
12989
- flex flex-col gap-2 py-2 px-3 transition-all duration-200
12990
- ${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
12991
- `
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"
12992
13247
  },
12993
- /* @__PURE__ */ import_react27.default.createElement(
12994
- "textarea",
13248
+ /* @__PURE__ */ import_react30.default.createElement(
13249
+ MentionEditor_default,
12995
13250
  {
12996
- ref: textareaRef,
12997
- className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
12998
- rows: 1,
12999
- style: {
13000
- minHeight: "1.5rem",
13001
- maxHeight: "250px"
13251
+ initialValue: group.text,
13252
+ onChange: (newText) => {
13253
+ if (canEdit) onUpdate(group.id, { ...group, text: newText });
13002
13254
  },
13003
- placeholder: canEdit ? "Escreva sobre este grupo..." : "",
13004
- value: group.text,
13005
- readOnly: !canEdit,
13006
- onChange: (e) => {
13007
- if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
13008
- }
13255
+ onPlay: onPlayAncestry,
13256
+ availableItems: availableMentionItems,
13257
+ canEdit,
13258
+ placeholder: "Escreva sobre este grupo... use @ para mencionar"
13009
13259
  }
13010
13260
  ),
13011
- group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
13012
- const isValid = anc.type === "ancestry" || !anc.type ? availableIds.has(String(anc.ancestry_id || anc.id)) : true;
13013
- const isAncestry = anc.type === "ancestry" || !anc.type;
13014
- const itemId = isAncestry ? anc.ancestry_id : anc.id;
13015
- let Icon = import_fi22.FiLayers;
13016
- let colorClass = "text-indigo-400";
13017
- if (anc.type === "quest") {
13018
- Icon = import_fi22.FiCheckSquare;
13019
- colorClass = "text-amber-400";
13020
- } else if (anc.type === "version") {
13021
- Icon = import_fi22.FiGitBranch;
13022
- colorClass = "text-purple-400";
13023
- } else if (anc.type === "node") {
13024
- Icon = import_fi22.FiBox;
13025
- colorClass = "text-emerald-400";
13026
- }
13027
- return /* @__PURE__ */ import_react27.default.createElement(
13028
- "div",
13029
- {
13030
- key: `${anc.type || "ancestry"}-${itemId}`,
13031
- className: `
13032
- flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
13033
- ${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
13034
- `,
13035
- title: isValid ? "" : "Esta informa\xE7\xE3o n\xE3o est\xE1 mais dispon\xEDvel neste contexto."
13036
- },
13037
- isValid ? /* @__PURE__ */ import_react27.default.createElement(
13038
- "button",
13039
- {
13040
- onClick: () => onPlayAncestry(anc),
13041
- className: `${colorClass} hover:text-white hover:bg-current/20 p-1 rounded transition-colors flex items-center justify-center`,
13042
- title: "Focar no cen\xE1rio"
13043
- },
13044
- /* @__PURE__ */ import_react27.default.createElement(Icon, { size: 12 }),
13045
- /* @__PURE__ */ import_react27.default.createElement(
13046
- import_fi22.FiPlay,
13047
- {
13048
- size: 8,
13049
- className: "ml-0.5 fill-current opacity-0 group-hover/card:opacity-100 transition-opacity"
13050
- }
13051
- )
13052
- ) : /* @__PURE__ */ import_react27.default.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiAlertTriangle, { size: 10 })),
13053
- /* @__PURE__ */ import_react27.default.createElement(
13054
- "span",
13055
- {
13056
- className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}`
13057
- },
13058
- anc.name
13059
- ),
13060
- canEdit && /* @__PURE__ */ import_react27.default.createElement(import_react27.default.Fragment, null, /* @__PURE__ */ import_react27.default.createElement(
13061
- "div",
13062
- {
13063
- className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}`
13064
- }
13065
- ), /* @__PURE__ */ import_react27.default.createElement(
13066
- "button",
13067
- {
13068
- onClick: () => onRemoveAncestry(group.id, itemId),
13069
- className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
13070
- title: "Remover men\xE7\xE3o"
13071
- },
13072
- /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiX, { size: 12 })
13073
- ))
13074
- );
13075
- })),
13076
- canEdit && /* @__PURE__ */ import_react27.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_react27.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react27.default.createElement(
13077
- "button",
13078
- {
13079
- onClick: () => onRequestPickAncestry(group.id),
13080
- className: `
13081
- flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors
13082
- ${isPickingForThisGroup ? "text-indigo-300 animate-pulse" : "text-slate-500 hover:text-indigo-300 hover:bg-indigo-500/10"}
13083
- `,
13084
- title: "Adicionar Men\xE7\xE3o a este grupo"
13085
- },
13086
- isPickingForThisGroup ? /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiCheckCircle, { size: 12 }) : /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiSearch, { size: 12 }),
13087
- isPickingForThisGroup ? "Selecionando..." : "Adicionar"
13088
- ), /* @__PURE__ */ import_react27.default.createElement(
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(
13089
13262
  "button",
13090
13263
  {
13091
13264
  onClick: () => onAddSubgroup(group.id),
13092
- className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
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",
13093
13266
  title: "Criar Subgrupo"
13094
13267
  },
13095
- /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlus, { size: 14 })
13096
- )), /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react27.default.createElement(
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(
13097
13271
  "button",
13098
13272
  {
13099
13273
  onClick: () => onIndent(group.id),
@@ -13101,25 +13275,25 @@ var GroupItem = ({
13101
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"}`,
13102
13276
  title: "Aninhar no grupo acima"
13103
13277
  },
13104
- /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiArrowRight, { size: 14 })
13105
- ), /* @__PURE__ */ import_react27.default.createElement(
13278
+ /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiArrowRight, { size: 14 })
13279
+ ), /* @__PURE__ */ import_react30.default.createElement(
13106
13280
  "button",
13107
13281
  {
13108
13282
  onClick: () => onOutdent(group.id),
13109
13283
  className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13110
13284
  title: "Desaninhar"
13111
13285
  },
13112
- /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiArrowLeft, { size: 14 })
13113
- ), /* @__PURE__ */ import_react27.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react27.default.createElement(
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(
13114
13288
  "button",
13115
13289
  {
13116
13290
  onClick: () => onDelete(group.id),
13117
13291
  className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
13118
13292
  title: "Remover Grupo"
13119
13293
  },
13120
- /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiTrash2, { size: 14 })
13294
+ /* @__PURE__ */ import_react30.default.createElement(import_fi23.FiTrash2, { size: 14 })
13121
13295
  )))
13122
- ), group.children && group.children.length > 0 && /* @__PURE__ */ import_react27.default.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ import_react27.default.createElement(
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(
13123
13297
  GroupItem,
13124
13298
  {
13125
13299
  key: childGroup.id,
@@ -13131,11 +13305,8 @@ var GroupItem = ({
13131
13305
  onAddSubgroup,
13132
13306
  onIndent,
13133
13307
  onOutdent,
13134
- onRemoveAncestry,
13135
- onRequestPickAncestry,
13136
- pickingGroupId,
13137
13308
  onPlayAncestry,
13138
- availableIds,
13309
+ availableMentionItems,
13139
13310
  canEdit
13140
13311
  }
13141
13312
  ))));
@@ -13150,21 +13321,19 @@ function AncestryBoard({
13150
13321
  onSave,
13151
13322
  userRole
13152
13323
  }) {
13153
- const [searchTerm, setSearchTerm] = (0, import_react27.useState)("");
13154
- const [groups, setGroups] = (0, import_react27.useState)([]);
13155
- const [isLoaded, setIsLoaded] = (0, import_react27.useState)(false);
13156
- const [pickingGroupId, setPickingGroupId] = (0, import_react27.useState)(null);
13157
- const [saveStatus, setSaveStatus] = (0, import_react27.useState)("idle");
13158
- const canEdit = (0, import_react27.useMemo)(() => {
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)(() => {
13159
13328
  return userRole !== "viewer";
13160
13329
  }, [userRole]);
13161
- (0, import_react27.useEffect)(() => {
13330
+ (0, import_react30.useEffect)(() => {
13162
13331
  if (initialGroups && !isLoaded) {
13163
13332
  setGroups(initialGroups);
13164
13333
  setIsLoaded(true);
13165
13334
  }
13166
13335
  }, [initialGroups, isLoaded]);
13167
- const nodeNamesMap = (0, import_react27.useMemo)(() => {
13336
+ const nodeNamesMap = (0, import_react30.useMemo)(() => {
13168
13337
  const map = /* @__PURE__ */ new Map();
13169
13338
  if (availableNodes && Array.isArray(availableNodes)) {
13170
13339
  availableNodes.forEach((node) => {
@@ -13175,10 +13344,10 @@ function AncestryBoard({
13175
13344
  }
13176
13345
  return map;
13177
13346
  }, [availableNodes]);
13178
- const availableIds = (0, import_react27.useMemo)(() => {
13347
+ const availableIds = (0, import_react30.useMemo)(() => {
13179
13348
  return new Set(availableAncestries.map((a) => String(a.ancestry_id)));
13180
13349
  }, [availableAncestries]);
13181
- const allMentionableItems = (0, import_react27.useMemo)(() => {
13350
+ const availableMentionItems = (0, import_react30.useMemo)(() => {
13182
13351
  const ancestries = availableAncestries.map((a) => ({
13183
13352
  id: String(a.ancestry_id),
13184
13353
  ancestry_id: a.ancestry_id,
@@ -13206,16 +13375,10 @@ function AncestryBoard({
13206
13375
  return groupList.map((g) => ({
13207
13376
  id: g.id,
13208
13377
  text: g.text || "",
13209
- ancestries: (g.ancestries || []).map((a) => ({
13210
- id: a.id || a.ancestry_id,
13211
- ancestry_id: a.ancestry_id,
13212
- name: a.name,
13213
- type: a.type || "ancestry"
13214
- })),
13215
13378
  children: sanitizeGroups(g.children || [])
13216
13379
  }));
13217
13380
  };
13218
- (0, import_react27.useEffect)(() => {
13381
+ (0, import_react30.useEffect)(() => {
13219
13382
  if (!isLoaded || !onSave) return;
13220
13383
  const timeoutId = setTimeout(async () => {
13221
13384
  setSaveStatus("saving");
@@ -13233,50 +13396,30 @@ function AncestryBoard({
13233
13396
  }, 3e3);
13234
13397
  return () => clearTimeout(timeoutId);
13235
13398
  }, [groups, isLoaded, onSave]);
13236
- (0, import_react27.useEffect)(() => {
13399
+ (0, import_react30.useEffect)(() => {
13237
13400
  if (!isOpen) return;
13238
13401
  const handleKeyDown = (e) => {
13239
13402
  if (e.key === "Escape") {
13240
- if (pickingGroupId) {
13241
- setPickingGroupId(null);
13242
- } else {
13243
- onClose();
13244
- }
13403
+ onClose();
13245
13404
  e.preventDefault();
13246
13405
  e.stopPropagation();
13247
13406
  }
13248
13407
  };
13249
13408
  window.addEventListener("keydown", handleKeyDown);
13250
13409
  return () => window.removeEventListener("keydown", handleKeyDown);
13251
- }, [isOpen, onClose, pickingGroupId]);
13252
- const filtered = (0, import_react27.useMemo)(() => {
13253
- const term = searchTerm.toLowerCase().trim();
13254
- return allMentionableItems.filter((item) => {
13255
- if (!term) return true;
13256
- const nameMatch = item.name && item.name.toLowerCase().includes(term);
13257
- const descMatch = item.description && item.description.toLowerCase().includes(term);
13258
- let parentMatch = false;
13259
- if (item.type === "ancestry") {
13260
- const parentName = nodeNamesMap.get(String(item.ancestral_node)) || "";
13261
- parentMatch = parentName.toLowerCase().includes(term);
13262
- }
13263
- return nameMatch || descMatch || parentMatch;
13264
- });
13265
- }, [allMentionableItems, searchTerm, nodeNamesMap]);
13410
+ }, [isOpen, onClose]);
13266
13411
  const handleAddRootGroup = () => {
13267
13412
  const newGroup = {
13268
- id: v4_default(),
13413
+ id: (0, import_uuid11.v4)(),
13269
13414
  text: "",
13270
- ancestries: [],
13271
13415
  children: []
13272
13416
  };
13273
13417
  setGroups((prev) => [newGroup, ...prev]);
13274
13418
  };
13275
13419
  const handleAddSubgroup = (parentId) => {
13276
13420
  const newGroup = {
13277
- id: v4_default(),
13421
+ id: (0, import_uuid11.v4)(),
13278
13422
  text: "",
13279
- ancestries: [],
13280
13423
  children: []
13281
13424
  };
13282
13425
  const addRecursive = (list) => {
@@ -13347,42 +13490,6 @@ function AncestryBoard({
13347
13490
  return newList;
13348
13491
  });
13349
13492
  };
13350
- const handleRequestPick = (groupId) => {
13351
- setPickingGroupId((prev) => prev === groupId ? null : groupId);
13352
- };
13353
- const handleSelectAncestry = (item) => {
13354
- if (pickingGroupId) {
13355
- setGroups((prev) => {
13356
- const addRecursive = (list) => {
13357
- return list.map((g) => {
13358
- if (g.id === pickingGroupId) {
13359
- const currentId = item.id;
13360
- const exists = g.ancestries.some(
13361
- (a) => (a.id || a.ancestry_id) === currentId && a.type === item.type
13362
- );
13363
- if (exists) return g;
13364
- return { ...g, ancestries: [...g.ancestries, item] };
13365
- }
13366
- return { ...g, children: addRecursive(g.children) };
13367
- });
13368
- };
13369
- return addRecursive(prev);
13370
- });
13371
- setPickingGroupId(null);
13372
- } else {
13373
- let fullItem = item;
13374
- if (item.type === "ancestry" || !item.type) {
13375
- fullItem = availableAncestries.find(
13376
- (a) => String(a.ancestry_id) === String(item.id || item.ancestry_id)
13377
- ) || item;
13378
- } else {
13379
- fullItem = availableNodes.find(
13380
- (n) => String(n.id) === String(item.id)
13381
- ) || item;
13382
- }
13383
- onSelect(fullItem);
13384
- }
13385
- };
13386
13493
  const handlePlayFromGroup = (item) => {
13387
13494
  let fullItem = item;
13388
13495
  if (item.type === "ancestry" || !item.type) {
@@ -13398,52 +13505,34 @@ function AncestryBoard({
13398
13505
  onSelect(fullItem);
13399
13506
  }
13400
13507
  };
13401
- const handleRemoveAncestryFromGroup = (groupId, itemId) => {
13402
- setGroups((prev) => {
13403
- const removeRecursive = (list) => {
13404
- return list.map((g) => {
13405
- if (g.id === groupId) {
13406
- return {
13407
- ...g,
13408
- ancestries: g.ancestries.filter(
13409
- (a) => (a.id || a.ancestry_id) !== itemId
13410
- )
13411
- };
13412
- }
13413
- return { ...g, children: removeRecursive(g.children) };
13414
- });
13415
- };
13416
- return removeRecursive(prev);
13417
- });
13418
- };
13419
13508
  if (!isOpen) return null;
13420
- return /* @__PURE__ */ import_react27.default.createElement(
13509
+ return /* @__PURE__ */ import_react30.default.createElement(
13421
13510
  "div",
13422
13511
  {
13423
13512
  className: "fixed inset-0 z-[2200] bg-black/80 backdrop-blur-sm flex items-center justify-center p-2",
13424
13513
  onClick: onClose
13425
13514
  },
13426
- /* @__PURE__ */ import_react27.default.createElement(
13515
+ /* @__PURE__ */ import_react30.default.createElement(
13427
13516
  "div",
13428
13517
  {
13429
- className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
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",
13430
13519
  onClick: (e) => e.stopPropagation()
13431
13520
  },
13432
- /* @__PURE__ */ import_react27.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_react27.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react27.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react27.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_react27.default.createElement(import_react27.default.Fragment, null, /* @__PURE__ */ import_react27.default.createElement(
13433
- import_fi22.FiLoader,
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(
13522
+ import_fi23.FiLoader,
13434
13523
  {
13435
13524
  className: "animate-spin text-indigo-400",
13436
13525
  size: 12
13437
13526
  }
13438
- ), /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react27.default.createElement(import_react27.default.Fragment, null, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react27.default.createElement(import_react27.default.Fragment, null, /* @__PURE__ */ import_react27.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ import_react27.default.createElement(
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(
13439
13528
  "button",
13440
13529
  {
13441
13530
  onClick: handleAddRootGroup,
13442
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 "
13443
13532
  },
13444
- /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlus, { size: 14, className: "text-indigo-400" }),
13445
- /* @__PURE__ */ import_react27.default.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
13446
- ), /* @__PURE__ */ import_react27.default.createElement(
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(
13447
13536
  "button",
13448
13537
  {
13449
13538
  onClick: onClose,
@@ -13451,128 +13540,37 @@ function AncestryBoard({
13451
13540
  },
13452
13541
  "\xD7"
13453
13542
  ))),
13454
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react27.default.createElement(
13455
- "div",
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(
13544
+ "button",
13456
13545
  {
13457
- className: `
13458
- flex flex-col border-r border-white/10 transition-all duration-300 flex-none
13459
- ${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
13460
- min-w-[280px] max-w-[500px] bg-slate-900
13461
- `
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"
13462
13548
  },
13463
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react27.default.createElement(
13464
- import_fi22.FiSearch,
13465
- {
13466
- className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}`
13467
- }
13468
- ), /* @__PURE__ */ import_react27.default.createElement(
13469
- "input",
13470
- {
13471
- type: "text",
13472
- placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar (Ancestralidades e Nodes)",
13473
- className: `
13474
- w-full rounded-md pl-9 pr-4 py-2 text-sm transition-all focus:outline-none focus:ring-1 focus:ring-indigo-500 border
13475
- ${pickingGroupId ? "bg-indigo-950/30 border-indigo-500/30 text-white placeholder-indigo-300/50" : "bg-slate-950 border-white/10 text-slate-200 placeholder-slate-600"}
13476
- `,
13477
- value: searchTerm,
13478
- onChange: (e) => setSearchTerm(e.target.value),
13479
- autoFocus: !pickingGroupId
13480
- }
13481
- ))),
13482
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((item) => {
13483
- const isPicking = !!pickingGroupId;
13484
- const isQuest = item.type === "quest";
13485
- const isVersion = item.type === "version";
13486
- const isNode = item.type === "node";
13487
- let Icon = import_fi22.FiLayers;
13488
- let colorClass = "bg-slate-800 text-indigo-400 border-white/5";
13489
- let pickingColorClass = "bg-indigo-500 text-white border-indigo-400";
13490
- let hoverClass = "hover:bg-indigo-600/10 hover:border-indigo-500/30";
13491
- let badge = null;
13492
- if (isQuest) {
13493
- Icon = import_fi22.FiCheckSquare;
13494
- colorClass = "bg-slate-800 text-amber-400 border-white/5";
13495
- pickingColorClass = "bg-amber-500 text-white border-amber-400";
13496
- hoverClass = "hover:bg-amber-500/10 hover:border-amber-500/30";
13497
- badge = "Quest";
13498
- } else if (isVersion) {
13499
- Icon = import_fi22.FiGitBranch;
13500
- colorClass = "bg-slate-800 text-purple-400 border-white/5";
13501
- pickingColorClass = "bg-purple-500 text-white border-purple-400";
13502
- hoverClass = "hover:bg-purple-500/10 hover:border-purple-500/30";
13503
- badge = "Ver";
13504
- } else if (isNode) {
13505
- Icon = import_fi22.FiBox;
13506
- colorClass = "bg-slate-800 text-emerald-400 border-white/5";
13507
- pickingColorClass = "bg-emerald-500 text-white border-emerald-400";
13508
- hoverClass = "hover:bg-emerald-500/10 hover:border-emerald-500/30";
13509
- badge = "Node";
13510
- }
13511
- return /* @__PURE__ */ import_react27.default.createElement(
13512
- "div",
13513
- {
13514
- key: `${item.type}-${item.id}`,
13515
- onClick: () => {
13516
- if (isPicking) handleSelectAncestry(item);
13517
- },
13518
- className: `
13519
- group relative flex items-start gap-3 p-3 text-left rounded-lg border transition-all duration-200
13520
- ${isPicking ? `border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer` : `border-white/5 bg-slate-800/40 ${hoverClass} cursor-default`}
13521
- `
13522
- },
13523
- /* @__PURE__ */ import_react27.default.createElement(
13524
- "div",
13525
- {
13526
- className: `
13527
- mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
13528
- ${isPicking ? pickingColorClass : `${colorClass} group-hover:bg-opacity-80`}
13529
- `
13530
- },
13531
- isPicking ? /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlus, { size: 16 }) : /* @__PURE__ */ import_react27.default.createElement(Icon, { size: 14 })
13532
- ),
13533
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react27.default.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, item.name || "Sem Nome"), badge && /* @__PURE__ */ import_react27.default.createElement("span", { className: `text-[9px] px-1 py-0.5 rounded ${isQuest ? "bg-amber-500/10 text-amber-400" : isVersion ? "bg-purple-500/10 text-purple-400" : "bg-emerald-500/10 text-emerald-400"} border border-current opacity-50` }, badge), item.is_private && /* @__PURE__ */ import_react27.default.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), item.type === "ancestry" && /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiCornerUpRight, { size: 10 }), /* @__PURE__ */ import_react27.default.createElement("span", { className: "truncate max-w-[120px]" }, nodeNamesMap.get(String(item.ancestral_node)) || "Node Desconhecido")), item.description && /* @__PURE__ */ import_react27.default.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, item.description)),
13534
- !isPicking && /* @__PURE__ */ import_react27.default.createElement(
13535
- "button",
13536
- {
13537
- onClick: (e) => {
13538
- e.stopPropagation();
13539
- handleSelectAncestry(item);
13540
- },
13541
- className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
13542
- title: "Renderizar / Focar"
13543
- },
13544
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiPlay, { size: 14, className: "ml-0.5" }))
13545
- )
13546
- );
13547
- }))
13548
- ), /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ import_react27.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ import_react27.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 m-4 bg-slate-900/20" }, /* @__PURE__ */ import_react27.default.createElement(import_fi22.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react27.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react27.default.createElement(import_react27.default.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ import_react27.default.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ import_react27.default.createElement(import_react27.default.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ import_react27.default.createElement(
13549
+ "Criar Primeiro Grupo"
13550
+ )) : groups.map((group, index) => /* @__PURE__ */ import_react30.default.createElement(
13549
13551
  GroupItem,
13550
13552
  {
13551
13553
  key: group.id,
13552
13554
  index,
13553
13555
  group,
13554
- siblings: groups,
13555
13556
  onUpdate: handleUpdateGroup,
13556
13557
  onDelete: handleDeleteGroup,
13557
13558
  onAddSubgroup: handleAddSubgroup,
13558
13559
  onIndent: handleIndent,
13559
13560
  onOutdent: handleOutdent,
13560
- onRemoveAncestry: handleRemoveAncestryFromGroup,
13561
- onRequestPickAncestry: handleRequestPick,
13562
- pickingGroupId,
13563
13561
  onPlayAncestry: handlePlayFromGroup,
13564
- availableIds,
13562
+ availableMentionItems,
13565
13563
  canEdit
13566
13564
  }
13567
13565
  ))))),
13568
- /* @__PURE__ */ import_react27.default.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-between flex-shrink-0" }, /* @__PURE__ */ import_react27.default.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ import_react27.default.createElement("span", null, groups.length, " grupos raiz"))
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"))
13569
13567
  )
13570
13568
  );
13571
13569
  }
13572
13570
 
13573
13571
  // src/components/MilestoneManager.jsx
13574
- var import_react28 = __toESM(require("react"));
13575
- var import_fi23 = require("react-icons/fi");
13572
+ var import_react31 = __toESM(require("react"));
13573
+ var import_fi24 = require("react-icons/fi");
13576
13574
  function MilestoneManager({
13577
13575
  isOpen,
13578
13576
  onClose,
@@ -13580,7 +13578,7 @@ function MilestoneManager({
13580
13578
  onUpdateMilestones = () => {
13581
13579
  }
13582
13580
  }) {
13583
- const [newMilestoneName, setNewMilestoneName] = (0, import_react28.useState)("");
13581
+ const [newMilestoneName, setNewMilestoneName] = (0, import_react31.useState)("");
13584
13582
  const handleAddMilestone = () => {
13585
13583
  if (!newMilestoneName.trim()) return;
13586
13584
  const newMilestone = {
@@ -13605,27 +13603,27 @@ function MilestoneManager({
13605
13603
  };
13606
13604
  if (!isOpen) return null;
13607
13605
  const swallow = (e) => e.stopPropagation();
13608
- return /* @__PURE__ */ import_react28.default.createElement(
13606
+ return /* @__PURE__ */ import_react31.default.createElement(
13609
13607
  "div",
13610
13608
  {
13611
13609
  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",
13612
13610
  onClick: onClose
13613
13611
  },
13614
- /* @__PURE__ */ import_react28.default.createElement(
13612
+ /* @__PURE__ */ import_react31.default.createElement(
13615
13613
  "div",
13616
13614
  {
13617
13615
  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",
13618
13616
  onClick: swallow
13619
13617
  },
13620
- /* @__PURE__ */ import_react28.default.createElement("div", { className: "px-6 py-4 border-b border-white/10 flex items-center justify-between" }, /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react28.default.createElement("div", { className: "p-2 rounded-lg bg-indigo-500/20 text-indigo-400" }, /* @__PURE__ */ import_react28.default.createElement(import_fi23.FiTarget, { size: 20 })), /* @__PURE__ */ import_react28.default.createElement("div", null, /* @__PURE__ */ import_react28.default.createElement("h2", { className: "text-lg font-semibold text-slate-100" }, "Milestones"), /* @__PURE__ */ import_react28.default.createElement("p", { className: "text-xs text-slate-400" }, "Gerencie os marcos do seu cen\xE1rio"))), /* @__PURE__ */ import_react28.default.createElement(
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(
13621
13619
  "button",
13622
13620
  {
13623
13621
  onClick: onClose,
13624
13622
  className: "p-2 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition-colors"
13625
13623
  },
13626
- /* @__PURE__ */ import_react28.default.createElement(import_fi23.FiX, { size: 20 })
13624
+ /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiX, { size: 20 })
13627
13625
  )),
13628
- /* @__PURE__ */ import_react28.default.createElement("div", { className: "px-6 py-5 bg-white/5 border-b border-white/5" }, /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ import_react28.default.createElement(
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(
13629
13627
  "input",
13630
13628
  {
13631
13629
  type: "text",
@@ -13635,47 +13633,47 @@ function MilestoneManager({
13635
13633
  placeholder: "Adicionar novo milestone...",
13636
13634
  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"
13637
13635
  }
13638
- ), /* @__PURE__ */ import_react28.default.createElement(
13636
+ ), /* @__PURE__ */ import_react31.default.createElement(
13639
13637
  "button",
13640
13638
  {
13641
13639
  onClick: handleAddMilestone,
13642
13640
  disabled: !newMilestoneName.trim(),
13643
13641
  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"
13644
13642
  },
13645
- /* @__PURE__ */ import_react28.default.createElement(import_fi23.FiPlus, { size: 18 }),
13643
+ /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiPlus, { size: 18 }),
13646
13644
  "Adicionar"
13647
13645
  ))),
13648
- /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex-1 overflow-y-auto px-6 py-4 custom-scrollbar" }, milestones.length > 0 ? /* @__PURE__ */ import_react28.default.createElement("div", { className: "space-y-3" }, milestones.map((ms) => /* @__PURE__ */ import_react28.default.createElement(
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(
13649
13647
  "div",
13650
13648
  {
13651
13649
  key: ms.id,
13652
13650
  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]"}`
13653
13651
  },
13654
- /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ import_react28.default.createElement(
13652
+ /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ import_react31.default.createElement(
13655
13653
  "div",
13656
13654
  {
13657
13655
  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"}`
13658
13656
  }
13659
- ), /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ import_react28.default.createElement("span", { className: `text-sm font-medium truncate ${ms.status === "active" ? "text-slate-100" : "text-slate-400 line-through"}` }, ms.name), /* @__PURE__ */ import_react28.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, ms.status === "active" ? "Ativo" : "Inativo"))),
13660
- /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react28.default.createElement(
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(
13661
13659
  "button",
13662
13660
  {
13663
13661
  onClick: () => handleToggleMilestoneStatus(ms.id),
13664
13662
  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"}`,
13665
13663
  title: ms.status === "active" ? "Inativar" : "Ativar"
13666
13664
  },
13667
- ms.status === "active" ? /* @__PURE__ */ import_react28.default.createElement(import_fi23.FiPauseCircle, { size: 18 }) : /* @__PURE__ */ import_react28.default.createElement(import_fi23.FiPlayCircle, { size: 18 })
13668
- ), /* @__PURE__ */ import_react28.default.createElement(
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(
13669
13667
  "button",
13670
13668
  {
13671
13669
  onClick: () => handleRemoveMilestone(ms.id),
13672
13670
  className: "p-2 rounded-lg hover:bg-red-500/20 text-slate-500 hover:text-red-400 transition-all",
13673
13671
  title: "Remover"
13674
13672
  },
13675
- /* @__PURE__ */ import_react28.default.createElement(import_fi23.FiTrash2, { size: 18 })
13673
+ /* @__PURE__ */ import_react31.default.createElement(import_fi24.FiTrash2, { size: 18 })
13676
13674
  ))
13677
- ))) : /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex flex-col items-center justify-center py-12 text-center" }, /* @__PURE__ */ import_react28.default.createElement("div", { className: "p-4 rounded-full bg-slate-800/30 text-slate-600 mb-4" }, /* @__PURE__ */ import_react28.default.createElement(import_fi23.FiTarget, { size: 40 })), /* @__PURE__ */ import_react28.default.createElement("h3", { className: "text-slate-400 font-medium" }, "Nenhum milestone definido"), /* @__PURE__ */ import_react28.default.createElement("p", { className: "text-xs text-slate-600 max-w-[200px] mt-1 italic" }, "Defina marcos importantes para orientar o progresso do projeto."))),
13678
- /* @__PURE__ */ import_react28.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_react28.default.createElement("div", { className: "flex gap-4" }, /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react28.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Total:"), /* @__PURE__ */ import_react28.default.createElement("span", { className: "text-xs font-bold text-slate-300" }, milestones.length)), /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react28.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Ativos:"), /* @__PURE__ */ import_react28.default.createElement("span", { className: "text-xs font-bold text-indigo-400" }, milestones.filter((m) => m.status === "active").length))))
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))))
13679
13677
  )
13680
13678
  );
13681
13679
  }
@@ -13762,12 +13760,12 @@ function XViewScene({
13762
13760
  get_view_members
13763
13761
  }) {
13764
13762
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
13765
- const { data: session, status } = (0, import_react30.useSession)();
13763
+ const { data: session, status } = (0, import_react33.useSession)();
13766
13764
  const router = (0, import_navigation.useRouter)();
13767
13765
  const searchParams = (0, import_navigation.useSearchParams)();
13768
13766
  const focusNodeId = searchParams == null ? void 0 : searchParams.get("focus");
13769
13767
  const focusAncestryId = searchParams == null ? void 0 : searchParams.get("ancestry");
13770
- const viewParams = (0, import_react29.useMemo)(() => {
13768
+ const viewParams = (0, import_react32.useMemo)(() => {
13771
13769
  if (encryptedConfig) {
13772
13770
  const data = decryptData(encryptedConfig);
13773
13771
  if (data) {
@@ -13776,7 +13774,7 @@ function XViewScene({
13776
13774
  }
13777
13775
  return null;
13778
13776
  }, [encryptedConfig, session]);
13779
- (0, import_react29.useEffect)(() => {
13777
+ (0, import_react32.useEffect)(() => {
13780
13778
  async function verifyPermission() {
13781
13779
  if (!viewParams || !session || !check_user_permission) return;
13782
13780
  const { id, type, owner_id } = viewParams;
@@ -13813,65 +13811,65 @@ function XViewScene({
13813
13811
  setIsLoading(false);
13814
13812
  }
13815
13813
  }, [viewParams, session, status, check_user_permission]);
13816
- const sceneConfigId = (0, import_react29.useMemo)(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
13817
- const ownerId = (0, import_react29.useMemo)(() => (viewParams == null ? void 0 : viewParams.owner_id) || null, [viewParams]);
13818
- const dbSaveUrl = (0, import_react29.useMemo)(() => {
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)(() => {
13819
13817
  if (ownerId && sceneConfigId) {
13820
13818
  return `x_view_dbs/${ownerId}/${sceneConfigId}`;
13821
13819
  }
13822
13820
  return null;
13823
13821
  }, [ownerId, sceneConfigId]);
13824
- const sceneSaveUrl = (0, import_react29.useMemo)(() => {
13822
+ const sceneSaveUrl = (0, import_react32.useMemo)(() => {
13825
13823
  if (ownerId && sceneConfigId) {
13826
13824
  return `x_view_scenes/${ownerId}/${sceneConfigId}`;
13827
13825
  }
13828
13826
  return null;
13829
13827
  }, [ownerId, sceneConfigId]);
13830
- const ancestry_save_url = (0, import_react29.useMemo)(() => {
13828
+ const ancestry_save_url = (0, import_react32.useMemo)(() => {
13831
13829
  if (ownerId && sceneConfigId) {
13832
13830
  return `x_view_ancestry/${ownerId}/${sceneConfigId}`;
13833
13831
  }
13834
13832
  return null;
13835
13833
  }, [ownerId, sceneConfigId]);
13836
- const sceneDataRef = (0, import_react29.useRef)(null);
13837
- const parentDataRef = (0, import_react29.useRef)(null);
13838
- const ancestryDataRef = (0, import_react29.useRef)(null);
13839
- const [isLoading, setIsLoading] = (0, import_react29.useState)(true);
13840
- const [permissionStatus, setPermissionStatus] = (0, import_react29.useState)("loading");
13841
- const [userPermissionRole, setUserPermissionRole] = (0, import_react29.useState)(null);
13842
- const [viewMembers, setViewMembers] = (0, import_react29.useState)([]);
13843
- const [isInitialized, setIsInitialized] = (0, import_react29.useState)(false);
13844
- const [sceneVersion, setSceneVersion] = (0, import_react29.useState)(0);
13845
- const [contextMenu, setContextMenu] = (0, import_react29.useState)({
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)({
13846
13844
  visible: false,
13847
13845
  x: 0,
13848
13846
  y: 0,
13849
13847
  nodeData: null
13850
13848
  });
13851
- const [multiContextMenu, setMultiContextMenu] = (0, import_react29.useState)({
13849
+ const [multiContextMenu, setMultiContextMenu] = (0, import_react32.useState)({
13852
13850
  visible: false,
13853
13851
  x: 0,
13854
13852
  y: 0,
13855
13853
  nodeIds: null
13856
13854
  });
13857
- const [relationshipMenu, setRelationshipMenu] = (0, import_react29.useState)({
13855
+ const [relationshipMenu, setRelationshipMenu] = (0, import_react32.useState)({
13858
13856
  visible: false,
13859
13857
  x: 0,
13860
13858
  y: 0,
13861
13859
  linkObject: null
13862
13860
  });
13863
- const [creationMode, setCreationMode] = (0, import_react29.useState)({
13861
+ const [creationMode, setCreationMode] = (0, import_react32.useState)({
13864
13862
  isActive: false,
13865
13863
  sourceNodeData: null
13866
13864
  });
13867
- const [versionMode, setVersionMode] = (0, import_react29.useState)({
13865
+ const [versionMode, setVersionMode] = (0, import_react32.useState)({
13868
13866
  isActive: false,
13869
13867
  sourceNodeData: null
13870
13868
  });
13871
- const [questMode, setQuestMode] = (0, import_react29.useState)({ isActive: false });
13872
- const [hasFocusedInitial, setHasFocusedInitial] = (0, import_react29.useState)(false);
13873
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0, import_react29.useState)(false);
13874
- const [ancestryMode, setAncestryMode] = (0, import_react29.useState)({
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)({
13875
13873
  isActive: false,
13876
13874
  tree: null,
13877
13875
  selectedParentId: null,
@@ -13882,42 +13880,42 @@ function XViewScene({
13882
13880
  ancestryDescriptionSections: [],
13883
13881
  isAddingNodes: false
13884
13882
  });
13885
- const [readingMode, setReadingMode] = (0, import_react29.useState)({
13883
+ const [readingMode, setReadingMode] = (0, import_react32.useState)({
13886
13884
  isActive: false,
13887
13885
  ancestry: null,
13888
13886
  branchStack: [],
13889
13887
  autoAbstraction: false
13890
13888
  });
13891
- const [formPosition, setFormPosition] = (0, import_react29.useState)({
13889
+ const [formPosition, setFormPosition] = (0, import_react32.useState)({
13892
13890
  left: 16,
13893
13891
  top: 16,
13894
13892
  opacity: 0
13895
13893
  });
13896
- const [detailsNode, setDetailsNode] = (0, import_react29.useState)(null);
13897
- const [detailsLink, setDetailsLink] = (0, import_react29.useState)(null);
13898
- const [ancestryLinkDetails, setAncestryLinkDetails] = (0, import_react29.useState)(null);
13899
- const [imageViewer, setImageViewer] = (0, import_react29.useState)({
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)({
13900
13898
  visible: false,
13901
13899
  images: [],
13902
13900
  startIndex: 0
13903
13901
  });
13904
- const [editingAncestryRel, setEditingAncestryRel] = (0, import_react29.useState)({
13902
+ const [editingAncestryRel, setEditingAncestryRel] = (0, import_react32.useState)({
13905
13903
  visible: false,
13906
13904
  data: null,
13907
13905
  path: null
13908
13906
  });
13909
- const [isImportModalOpen, setIsImportModalOpen] = (0, import_react29.useState)(false);
13910
- const [importSuccessMessage, setImportSuccessMessage] = (0, import_react29.useState)("");
13911
- const [invalidTargetError, setInvalidTargetError] = (0, import_react29.useState)(null);
13912
- const [highlightedNodeId, setHighlightedNodeId] = (0, import_react29.useState)(null);
13913
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = (0, import_react29.useState)(false);
13914
- const [ancestryBoardData, setAncestryBoardData] = (0, import_react29.useState)([]);
13915
- const [isSidebarOpen, setIsSidebarOpen] = (0, import_react29.useState)(false);
13916
- const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] = (0, import_react29.useState)(false);
13917
- const mountRef = (0, import_react29.useRef)(null);
13918
- const tooltipRef = (0, import_react29.useRef)(null);
13919
- const formRef = (0, import_react29.useRef)(null);
13920
- const stateRef = (0, import_react29.useRef)({
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)({
13921
13919
  readMode: {
13922
13920
  currentMaxIndex: 0,
13923
13921
  progressMap: {}
@@ -13981,10 +13979,10 @@ function XViewScene({
13981
13979
  minWidth: 320,
13982
13980
  maxWidth: maxReadPanelW
13983
13981
  });
13984
- (0, import_react29.useEffect)(() => {
13982
+ (0, import_react32.useEffect)(() => {
13985
13983
  stateRef.current.ancestry = ancestryMode;
13986
13984
  }, [ancestryMode]);
13987
- (0, import_react29.useEffect)(() => {
13985
+ (0, import_react32.useEffect)(() => {
13988
13986
  var _a2;
13989
13987
  if (!isInitialized) return;
13990
13988
  const map = /* @__PURE__ */ new Map();
@@ -14007,10 +14005,10 @@ function XViewScene({
14007
14005
  }
14008
14006
  stateRef.current.nodeIdToParentFileMap = map;
14009
14007
  }, [isInitialized, sceneVersion]);
14010
- const handleNavigateBack = (0, import_react29.useCallback)(() => {
14008
+ const handleNavigateBack = (0, import_react32.useCallback)(() => {
14011
14009
  router.push("/dashboard/scenes");
14012
14010
  }, [router]);
14013
- const handleConfirmImport = (0, import_react29.useCallback)(
14011
+ const handleConfirmImport = (0, import_react32.useCallback)(
14014
14012
  async (importPayload) => {
14015
14013
  var _a2, _b2;
14016
14014
  let files = [];
@@ -14138,7 +14136,7 @@ function XViewScene({
14138
14136
  const handleOpenImageViewer = (images, startIndex) => {
14139
14137
  setImageViewer({ visible: true, images, startIndex });
14140
14138
  };
14141
- const tweenToTarget = (0, import_react29.useCallback)(
14139
+ const tweenToTarget = (0, import_react32.useCallback)(
14142
14140
  (target, zoomFactor = 1, forcedDirection = null) => {
14143
14141
  const { camera, controls, tweenGroup } = stateRef.current;
14144
14142
  if (!camera || !controls || !tweenGroup) return;
@@ -14164,7 +14162,7 @@ function XViewScene({
14164
14162
  if (!t || typeof t.closest !== "function") return false;
14165
14163
  return !!t.closest(".ui-overlay");
14166
14164
  };
14167
- const buildFullAncestryTree = (0, import_react29.useCallback)(
14165
+ const buildFullAncestryTree = (0, import_react32.useCallback)(
14168
14166
  (idTree, nodes, ancestries = []) => {
14169
14167
  if (!idTree) return null;
14170
14168
  const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
@@ -14249,7 +14247,7 @@ function XViewScene({
14249
14247
  },
14250
14248
  []
14251
14249
  );
14252
- const handleActivateTimeline = (0, import_react29.useCallback)(() => {
14250
+ const handleActivateTimeline = (0, import_react32.useCallback)(() => {
14253
14251
  const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
14254
14252
  if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
14255
14253
  while (timelineIntervalsGroup.children.length > 0) {
@@ -14409,7 +14407,7 @@ function XViewScene({
14409
14407
  }
14410
14408
  });
14411
14409
  }, []);
14412
- const handleVersionTimeline = (0, import_react29.useCallback)((sourceMesh, versionMeshes) => {
14410
+ const handleVersionTimeline = (0, import_react32.useCallback)((sourceMesh, versionMeshes) => {
14413
14411
  const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
14414
14412
  if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
14415
14413
  return;
@@ -14546,7 +14544,7 @@ function XViewScene({
14546
14544
  }
14547
14545
  });
14548
14546
  }, []);
14549
- (0, import_react29.useEffect)(() => {
14547
+ (0, import_react32.useEffect)(() => {
14550
14548
  async function fetchAllData(configPath, ownerId2) {
14551
14549
  var _a2, _b2;
14552
14550
  if (!get_scene_view_data) {
@@ -14651,12 +14649,12 @@ function XViewScene({
14651
14649
  focusNodeId,
14652
14650
  focusAncestryId
14653
14651
  ]);
14654
- const isNodeInView = (0, import_react29.useCallback)((id) => {
14652
+ const isNodeInView = (0, import_react32.useCallback)((id) => {
14655
14653
  const key = String(id);
14656
14654
  const objs = stateRef.current.nodeObjects || {};
14657
14655
  return !!objs[key];
14658
14656
  }, []);
14659
- const addOrUpdateNodeMesh = (0, import_react29.useCallback)(
14657
+ const addOrUpdateNodeMesh = (0, import_react32.useCallback)(
14660
14658
  (nodeData, position, suppressVersionUpdate = false, forceShowQuestDate = false) => {
14661
14659
  const {
14662
14660
  graphGroup,
@@ -14697,7 +14695,7 @@ function XViewScene({
14697
14695
  },
14698
14696
  []
14699
14697
  );
14700
- const handleActivateQuestLens = (0, import_react29.useCallback)(({ assigneeId, status: status2, milestoneId }) => {
14698
+ const handleActivateQuestLens = (0, import_react32.useCallback)(({ assigneeId, status: status2, milestoneId }) => {
14701
14699
  var _a2;
14702
14700
  const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
14703
14701
  if (!nodeObjects || !tweenGroup || !graphGroup) return;
@@ -14911,7 +14909,7 @@ function XViewScene({
14911
14909
  camTween.start();
14912
14910
  }
14913
14911
  }, [addOrUpdateNodeMesh]);
14914
- (0, import_react29.useEffect)(() => {
14912
+ (0, import_react32.useEffect)(() => {
14915
14913
  if (!isInitialized || !sceneDataRef.current) return;
14916
14914
  const currentMount = mountRef.current;
14917
14915
  if (!currentMount) return;
@@ -15667,7 +15665,7 @@ function XViewScene({
15667
15665
  get_scene_view_data,
15668
15666
  save_view_data
15669
15667
  ]);
15670
- const handleGhostNodeImageChange = (0, import_react29.useCallback)((useImage, imageUrl) => {
15668
+ const handleGhostNodeImageChange = (0, import_react32.useCallback)((useImage, imageUrl) => {
15671
15669
  const {
15672
15670
  node: ghostNode,
15673
15671
  line: ghostLine,
@@ -15715,7 +15713,7 @@ function XViewScene({
15715
15713
  aura: newGhostNode.getObjectByName("aura")
15716
15714
  };
15717
15715
  }, []);
15718
- const handleGhostNodeIntensityChange = (0, import_react29.useCallback)((newIntensity) => {
15716
+ const handleGhostNodeIntensityChange = (0, import_react32.useCallback)((newIntensity) => {
15719
15717
  const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
15720
15718
  if (!ghostNode) return;
15721
15719
  const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
@@ -15736,7 +15734,7 @@ function XViewScene({
15736
15734
  ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
15737
15735
  }
15738
15736
  }, []);
15739
- const handleDetailNodeIntensityChange = (0, import_react29.useCallback)(
15737
+ const handleDetailNodeIntensityChange = (0, import_react32.useCallback)(
15740
15738
  (nodeId, newIntensity) => {
15741
15739
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
15742
15740
  if (!mesh) return;
@@ -15892,7 +15890,7 @@ function XViewScene({
15892
15890
  mountRef.current.style.cursor = "default";
15893
15891
  }
15894
15892
  };
15895
- const handleAncestryTreeUpdate = (0, import_react29.useCallback)((newTree, extraData = null) => {
15893
+ const handleAncestryTreeUpdate = (0, import_react32.useCallback)((newTree, extraData = null) => {
15896
15894
  setAncestryMode((prev) => {
15897
15895
  const prevTreeStr = JSON.stringify(prev.tree);
15898
15896
  const newTreeStr = JSON.stringify(newTree);
@@ -15915,7 +15913,7 @@ function XViewScene({
15915
15913
  };
15916
15914
  });
15917
15915
  }, []);
15918
- const actionHandlerContext = (0, import_react29.useMemo)(
15916
+ const actionHandlerContext = (0, import_react32.useMemo)(
15919
15917
  () => {
15920
15918
  var _a2;
15921
15919
  return {
@@ -15976,7 +15974,7 @@ function XViewScene({
15976
15974
  const handleStartVersioning = (nodeData) => {
15977
15975
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
15978
15976
  };
15979
- const handleStartQuestQuick = (0, import_react29.useCallback)((questNode) => {
15977
+ const handleStartQuestQuick = (0, import_react32.useCallback)((questNode) => {
15980
15978
  var _a2, _b2, _c2;
15981
15979
  if (!questNode || !actionHandlerContext) return;
15982
15980
  const allParentNodes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
@@ -16011,7 +16009,7 @@ function XViewScene({
16011
16009
  }
16012
16010
  setDetailsNode(updatedNode);
16013
16011
  }, [session, actionHandlerContext]);
16014
- const handleFinishQuestQuick = (0, import_react29.useCallback)((questNode) => {
16012
+ const handleFinishQuestQuick = (0, import_react32.useCallback)((questNode) => {
16015
16013
  var _a2, _b2, _c2, _d2;
16016
16014
  if (!questNode || !actionHandlerContext) return;
16017
16015
  const {
@@ -16085,7 +16083,7 @@ function XViewScene({
16085
16083
  setDetailsNode(null);
16086
16084
  }
16087
16085
  }, [session, actionHandlerContext, viewMembers, detailsNode]);
16088
- const handleCancelQuest = (0, import_react29.useCallback)(() => {
16086
+ const handleCancelQuest = (0, import_react32.useCallback)(() => {
16089
16087
  const { graphGroup, ghostElements } = stateRef.current;
16090
16088
  if (ghostElements.node && graphGroup) {
16091
16089
  if (ghostElements.node.userData.labelObject) {
@@ -16240,7 +16238,7 @@ function XViewScene({
16240
16238
  }
16241
16239
  userActionHandlers.handleCancelConnection(context);
16242
16240
  };
16243
- const handleClearAncestryVisuals = (0, import_react29.useCallback)((ancestryId) => {
16241
+ const handleClearAncestryVisuals = (0, import_react32.useCallback)((ancestryId) => {
16244
16242
  const { renderedAncestries, ancestryGroup } = stateRef.current;
16245
16243
  const renderIndex = renderedAncestries.findIndex(
16246
16244
  (a) => String(a.id) === String(ancestryId)
@@ -16258,7 +16256,7 @@ function XViewScene({
16258
16256
  );
16259
16257
  }
16260
16258
  }, []);
16261
- const handleRenderAncestry = (0, import_react29.useCallback)(
16259
+ const handleRenderAncestry = (0, import_react32.useCallback)(
16262
16260
  async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
16263
16261
  setContextMenu(
16264
16262
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -16752,7 +16750,7 @@ function XViewScene({
16752
16750
  ancestryMode.isActive
16753
16751
  ]
16754
16752
  );
16755
- const handleRenderAbstractionTree = (0, import_react29.useCallback)(
16753
+ const handleRenderAbstractionTree = (0, import_react32.useCallback)(
16756
16754
  (ancestryObject, targetNodeId = null) => {
16757
16755
  setContextMenu(
16758
16756
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -16840,7 +16838,7 @@ function XViewScene({
16840
16838
  handleClearAncestryVisuals
16841
16839
  ]
16842
16840
  );
16843
- const handleReadModeBranchNav = (0, import_react29.useCallback)(
16841
+ const handleReadModeBranchNav = (0, import_react32.useCallback)(
16844
16842
  (nodeId, action, direction = "right") => {
16845
16843
  const { ancestry, branchStack } = readingMode;
16846
16844
  if (!ancestry || !ancestry.tree) return;
@@ -17018,13 +17016,13 @@ function XViewScene({
17018
17016
  },
17019
17017
  [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]
17020
17018
  );
17021
- const handleReadModeHighlight = (0, import_react29.useCallback)((nodeId) => {
17019
+ const handleReadModeHighlight = (0, import_react32.useCallback)((nodeId) => {
17022
17020
  if (stateRef.current.highlightedNodeId !== nodeId) {
17023
17021
  stateRef.current.highlightedNodeId = nodeId;
17024
17022
  }
17025
17023
  setHighlightedNodeId(nodeId);
17026
17024
  }, []);
17027
- const activeNodeBranches = (0, import_react29.useMemo)(() => {
17025
+ const activeNodeBranches = (0, import_react32.useMemo)(() => {
17028
17026
  if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
17029
17027
  return null;
17030
17028
  const fullTree = buildFullAncestryTree(
@@ -17068,7 +17066,7 @@ function XViewScene({
17068
17066
  readingMode.branchStack,
17069
17067
  ancestryDataRef.current
17070
17068
  ]);
17071
- const backNavigationInfo = (0, import_react29.useMemo)(() => {
17069
+ const backNavigationInfo = (0, import_react32.useMemo)(() => {
17072
17070
  const { branchStack } = readingMode;
17073
17071
  if (!branchStack || branchStack.length === 0) return null;
17074
17072
  const lastStep = branchStack[branchStack.length - 1];
@@ -17079,7 +17077,7 @@ function XViewScene({
17079
17077
  name: "Voltar para anterior"
17080
17078
  };
17081
17079
  }, [readingMode.branchStack]);
17082
- const getReadModeDisplayContext = (0, import_react29.useMemo)(() => {
17080
+ const getReadModeDisplayContext = (0, import_react32.useMemo)(() => {
17083
17081
  const { ancestry, branchStack } = readingMode;
17084
17082
  if (!ancestry) return null;
17085
17083
  if (branchStack.length === 0) {
@@ -17122,7 +17120,7 @@ function XViewScene({
17122
17120
  customProperties: branchProps
17123
17121
  };
17124
17122
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
17125
- const readModeAbstractionTree = (0, import_react29.useMemo)(() => {
17123
+ const readModeAbstractionTree = (0, import_react32.useMemo)(() => {
17126
17124
  if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
17127
17125
  return null;
17128
17126
  }
@@ -17141,7 +17139,7 @@ function XViewScene({
17141
17139
  buildFullAncestryTree,
17142
17140
  sceneVersion
17143
17141
  ]);
17144
- const handleStartReadingAncestry = (0, import_react29.useCallback)(
17142
+ const handleStartReadingAncestry = (0, import_react32.useCallback)(
17145
17143
  async (ancestryObject, renderMode = "full") => {
17146
17144
  setContextMenu(
17147
17145
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -17184,7 +17182,7 @@ function XViewScene({
17184
17182
  },
17185
17183
  [handleRenderAncestry, handleRenderAbstractionTree]
17186
17184
  );
17187
- const handleReadModeSectionChange = (0, import_react29.useCallback)(
17185
+ const handleReadModeSectionChange = (0, import_react32.useCallback)(
17188
17186
  (activeSectionId) => {
17189
17187
  const { ancestry, branchStack } = readingMode;
17190
17188
  if (!ancestry || !readingMode.isActive) return;
@@ -17269,10 +17267,10 @@ function XViewScene({
17269
17267
  ancestryDataRef.current
17270
17268
  ]
17271
17269
  );
17272
- const handleCloseReadMode = (0, import_react29.useCallback)(() => {
17270
+ const handleCloseReadMode = (0, import_react32.useCallback)(() => {
17273
17271
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
17274
17272
  }, []);
17275
- const handleAncestrySectionChange = (0, import_react29.useCallback)(
17273
+ const handleAncestrySectionChange = (0, import_react32.useCallback)(
17276
17274
  (activeSectionId, ancestryOverride = null, rotation = 0) => {
17277
17275
  var _a2, _b2;
17278
17276
  const currentMode = stateRef.current.ancestry;
@@ -17334,7 +17332,7 @@ function XViewScene({
17334
17332
  },
17335
17333
  [handleRenderAncestry]
17336
17334
  );
17337
- const handleEditAncestry = (0, import_react29.useCallback)(
17335
+ const handleEditAncestry = (0, import_react32.useCallback)(
17338
17336
  async (ancestryObject) => {
17339
17337
  setContextMenu(
17340
17338
  (prev) => prev.visible ? { ...prev, visible: false } : prev
@@ -17389,7 +17387,7 @@ function XViewScene({
17389
17387
  const handleSelectAncestryParent = (nodeId) => {
17390
17388
  setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
17391
17389
  };
17392
- const handleRemoveFromAncestry = (0, import_react29.useCallback)((pathToRemove) => {
17390
+ const handleRemoveFromAncestry = (0, import_react32.useCallback)((pathToRemove) => {
17393
17391
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
17394
17392
  console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
17395
17393
  return;
@@ -17414,7 +17412,7 @@ function XViewScene({
17414
17412
  return { ...prev, tree: newTree };
17415
17413
  });
17416
17414
  }, []);
17417
- const handleSaveAncestry = (0, import_react29.useCallback)(
17415
+ const handleSaveAncestry = (0, import_react32.useCallback)(
17418
17416
  async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
17419
17417
  const treeToUse = treeOverride || ancestryMode.tree;
17420
17418
  const { isEditMode, currentAncestryId } = ancestryMode;
@@ -17650,7 +17648,7 @@ function XViewScene({
17650
17648
  });
17651
17649
  setEditingAncestryRel({ visible: false, data: null, path: null });
17652
17650
  };
17653
- const handleDeleteAncestry = (0, import_react29.useCallback)(
17651
+ const handleDeleteAncestry = (0, import_react32.useCallback)(
17654
17652
  async (ancestryIdToDelete) => {
17655
17653
  if (!ancestryIdToDelete) {
17656
17654
  alert("ID da ancestralidade n\xE3o encontrado.");
@@ -17732,10 +17730,10 @@ function XViewScene({
17732
17730
  },
17733
17731
  [save_view_data, delete_file_action]
17734
17732
  );
17735
- const handleOpenAncestryBoard = (0, import_react29.useCallback)(() => {
17733
+ const handleOpenAncestryBoard = (0, import_react32.useCallback)(() => {
17736
17734
  setIsAncestryBoardOpen(true);
17737
17735
  }, []);
17738
- const handleSelectAncestryFromBoard = (0, import_react29.useCallback)(
17736
+ const handleSelectAncestryFromBoard = (0, import_react32.useCallback)(
17739
17737
  (item) => {
17740
17738
  setIsAncestryBoardOpen(false);
17741
17739
  setIsSidebarOpen(false);
@@ -17753,7 +17751,7 @@ function XViewScene({
17753
17751
  },
17754
17752
  [handleStartReadingAncestry, tweenToTarget]
17755
17753
  );
17756
- const handleSaveAncestryBoard = (0, import_react29.useCallback)(
17754
+ const handleSaveAncestryBoard = (0, import_react32.useCallback)(
17757
17755
  async (groups) => {
17758
17756
  if (!sceneConfigId || !viewParams || !session) return;
17759
17757
  const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
@@ -17767,7 +17765,7 @@ function XViewScene({
17767
17765
  },
17768
17766
  [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]
17769
17767
  );
17770
- const existingNodeTypes = (0, import_react29.useMemo)(() => {
17768
+ const existingNodeTypes = (0, import_react32.useMemo)(() => {
17771
17769
  if (!parentDataRef.current) {
17772
17770
  return [];
17773
17771
  }
@@ -17779,7 +17777,7 @@ function XViewScene({
17779
17777
  ).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
17780
17778
  return [...new Set(allTypes)];
17781
17779
  }, [parentDataRef.current, sceneVersion]);
17782
- const searchableDbNodes = (0, import_react29.useMemo)(() => {
17780
+ const searchableDbNodes = (0, import_react32.useMemo)(() => {
17783
17781
  var _a2;
17784
17782
  if (!parentDataRef.current) {
17785
17783
  return [];
@@ -17800,7 +17798,7 @@ function XViewScene({
17800
17798
  return !((_a3 = node.version_node) == null ? void 0 : _a3.is_version);
17801
17799
  });
17802
17800
  }, [parentDataRef.current, (_b = sceneDataRef.current) == null ? void 0 : _b.quest_nodes, sceneVersion]);
17803
- const handleAddExistingNode = (0, import_react29.useCallback)(
17801
+ const handleAddExistingNode = (0, import_react32.useCallback)(
17804
17802
  (nodeId) => {
17805
17803
  return userActionHandlers.handleAddExistingNodeById(
17806
17804
  actionHandlerContext,
@@ -17809,7 +17807,7 @@ function XViewScene({
17809
17807
  },
17810
17808
  [actionHandlerContext]
17811
17809
  );
17812
- const handleUpdateMilestones = (0, import_react29.useCallback)(
17810
+ const handleUpdateMilestones = (0, import_react32.useCallback)(
17813
17811
  async (newMilestones) => {
17814
17812
  var _a2, _b2, _c2;
17815
17813
  if (!sceneDataRef.current) return;
@@ -17855,7 +17853,7 @@ function XViewScene({
17855
17853
  viewParams == null ? void 0 : viewParams.type
17856
17854
  ]
17857
17855
  );
17858
- const handleSaveCurrentView = (0, import_react29.useCallback)(async () => {
17856
+ const handleSaveCurrentView = (0, import_react32.useCallback)(async () => {
17859
17857
  var _a2, _b2, _c2;
17860
17858
  const { nodeObjects, allLinks } = stateRef.current;
17861
17859
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
@@ -17898,16 +17896,16 @@ function XViewScene({
17898
17896
  console.error("Erro na chamada de save_view_data:", error);
17899
17897
  }
17900
17898
  }, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
17901
- const allAvailableNodes = (0, import_react29.useMemo)(() => {
17899
+ const allAvailableNodes = (0, import_react32.useMemo)(() => {
17902
17900
  if (!parentDataRef.current) return [];
17903
17901
  return Object.values(parentDataRef.current).flatMap(
17904
17902
  (fileData) => fileData.nodes || []
17905
17903
  );
17906
17904
  }, [sceneVersion, isInitialized]);
17907
- const allAvailableAncestries = (0, import_react29.useMemo)(() => {
17905
+ const allAvailableAncestries = (0, import_react32.useMemo)(() => {
17908
17906
  return ancestryDataRef.current || [];
17909
17907
  }, [sceneVersion, isInitialized]);
17910
- const handleOpenReference = (0, import_react29.useCallback)(
17908
+ const handleOpenReference = (0, import_react32.useCallback)(
17911
17909
  (referenceData) => {
17912
17910
  const { type, id } = referenceData;
17913
17911
  if (type === "node") {
@@ -17946,13 +17944,13 @@ function XViewScene({
17946
17944
  tweenToTarget
17947
17945
  ]
17948
17946
  );
17949
- const handleToggleAncestryAddMode = (0, import_react29.useCallback)(() => {
17947
+ const handleToggleAncestryAddMode = (0, import_react32.useCallback)(() => {
17950
17948
  setAncestryMode((prev) => ({
17951
17949
  ...prev,
17952
17950
  isAddingNodes: !prev.isAddingNodes
17953
17951
  }));
17954
17952
  }, []);
17955
- const handleFocusNode = (0, import_react29.useCallback)(
17953
+ const handleFocusNode = (0, import_react32.useCallback)(
17956
17954
  (nodeData) => {
17957
17955
  var _a2;
17958
17956
  if (!nodeData) return;
@@ -17968,7 +17966,7 @@ function XViewScene({
17968
17966
  },
17969
17967
  [tweenToTarget]
17970
17968
  );
17971
- const availableDatasets = (0, import_react29.useMemo)(() => {
17969
+ const availableDatasets = (0, import_react32.useMemo)(() => {
17972
17970
  if (!sceneDataRef.current || !parentDataRef.current) return [];
17973
17971
  return sceneDataRef.current.parent_dbs.map((db) => {
17974
17972
  var _a2;
@@ -17982,7 +17980,7 @@ function XViewScene({
17982
17980
  String(creationMode.sourceNodeData.id)
17983
17981
  )) == null ? void 0 : _c.parentFileId : null;
17984
17982
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
17985
- (0, import_react29.useEffect)(() => {
17983
+ (0, import_react32.useEffect)(() => {
17986
17984
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
17987
17985
  const nodeObjects = stateRef.current.nodeObjects || {};
17988
17986
  const targetMesh = nodeObjects[String(focusNodeId)];
@@ -18005,7 +18003,7 @@ function XViewScene({
18005
18003
  hasFocusedInitial,
18006
18004
  tweenToTarget
18007
18005
  ]);
18008
- (0, import_react29.useEffect)(() => {
18006
+ (0, import_react32.useEffect)(() => {
18009
18007
  if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
18010
18008
  const ancestries = ancestryDataRef.current || [];
18011
18009
  const targetAncestry = ancestries.find(
@@ -18030,7 +18028,7 @@ function XViewScene({
18030
18028
  hasOpenedInitialAncestry,
18031
18029
  handleStartReadingAncestry
18032
18030
  ]);
18033
- (0, import_react29.useEffect)(() => {
18031
+ (0, import_react32.useEffect)(() => {
18034
18032
  function handleKeyDown(event) {
18035
18033
  var _a2, _b2, _c2;
18036
18034
  const context = actionHandlerContext;
@@ -18153,10 +18151,10 @@ function XViewScene({
18153
18151
  // <-- handleCancelQuest adicionado aqui
18154
18152
  ]);
18155
18153
  if (isLoading || status === "loading" || permissionStatus === "loading") {
18156
- return /* @__PURE__ */ import_react29.default.createElement(LoadingScreen, null);
18154
+ return /* @__PURE__ */ import_react32.default.createElement(LoadingScreen, null);
18157
18155
  }
18158
18156
  if (permissionStatus === "denied") {
18159
- return /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react29.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_react29.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react29.default.createElement(
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(
18160
18158
  "svg",
18161
18159
  {
18162
18160
  xmlns: "http://www.w3.org/2000/svg",
@@ -18166,7 +18164,7 @@ function XViewScene({
18166
18164
  stroke: "currentColor",
18167
18165
  className: "w-16 h-16 mx-auto"
18168
18166
  },
18169
- /* @__PURE__ */ import_react29.default.createElement(
18167
+ /* @__PURE__ */ import_react32.default.createElement(
18170
18168
  "path",
18171
18169
  {
18172
18170
  strokeLinecap: "round",
@@ -18174,13 +18172,13 @@ function XViewScene({
18174
18172
  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"
18175
18173
  }
18176
18174
  )
18177
- )), /* @__PURE__ */ import_react29.default.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ import_react29.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_react29.default.createElement(
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(
18178
18176
  "button",
18179
18177
  {
18180
18178
  onClick: () => router.push("/dashboard/scenes"),
18181
18179
  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"
18182
18180
  },
18183
- /* @__PURE__ */ import_react29.default.createElement(
18181
+ /* @__PURE__ */ import_react32.default.createElement(
18184
18182
  "svg",
18185
18183
  {
18186
18184
  xmlns: "http://www.w3.org/2000/svg",
@@ -18190,7 +18188,7 @@ function XViewScene({
18190
18188
  stroke: "currentColor",
18191
18189
  className: "w-5 h-5"
18192
18190
  },
18193
- /* @__PURE__ */ import_react29.default.createElement(
18191
+ /* @__PURE__ */ import_react32.default.createElement(
18194
18192
  "path",
18195
18193
  {
18196
18194
  strokeLinecap: "round",
@@ -18202,7 +18200,7 @@ function XViewScene({
18202
18200
  "Voltar para Scenes"
18203
18201
  )));
18204
18202
  }
18205
- return /* @__PURE__ */ import_react29.default.createElement(
18203
+ return /* @__PURE__ */ import_react32.default.createElement(
18206
18204
  "div",
18207
18205
  {
18208
18206
  ref: mountRef,
@@ -18214,7 +18212,7 @@ function XViewScene({
18214
18212
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
18215
18213
  }
18216
18214
  },
18217
- userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react29.default.createElement(
18215
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react32.default.createElement(
18218
18216
  XViewSidebar,
18219
18217
  {
18220
18218
  dbNodes: searchableDbNodes,
@@ -18238,7 +18236,7 @@ function XViewScene({
18238
18236
  onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
18239
18237
  }
18240
18238
  ),
18241
- creationMode.isActive && /* @__PURE__ */ import_react29.default.createElement(
18239
+ creationMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
18242
18240
  InSceneCreationForm,
18243
18241
  {
18244
18242
  onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
@@ -18270,7 +18268,7 @@ function XViewScene({
18270
18268
  availableAncestries: allAvailableAncestries
18271
18269
  }
18272
18270
  ),
18273
- versionMode.isActive && /* @__PURE__ */ import_react29.default.createElement(
18271
+ versionMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
18274
18272
  InSceneVersionForm,
18275
18273
  {
18276
18274
  onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
@@ -18296,7 +18294,7 @@ function XViewScene({
18296
18294
  availableAncestries: allAvailableAncestries
18297
18295
  }
18298
18296
  ),
18299
- questMode.isActive && /* @__PURE__ */ import_react29.default.createElement(
18297
+ questMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
18300
18298
  InSceneQuestForm,
18301
18299
  {
18302
18300
  onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
@@ -18324,7 +18322,7 @@ function XViewScene({
18324
18322
  onUpdateMilestones: handleUpdateMilestones
18325
18323
  }
18326
18324
  ),
18327
- readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react29.default.createElement(
18325
+ readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react32.default.createElement(
18328
18326
  "div",
18329
18327
  {
18330
18328
  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"}`,
@@ -18337,7 +18335,7 @@ function XViewScene({
18337
18335
  maxWidth: "92vw"
18338
18336
  }
18339
18337
  },
18340
- /* @__PURE__ */ import_react29.default.createElement(
18338
+ /* @__PURE__ */ import_react32.default.createElement(
18341
18339
  "div",
18342
18340
  {
18343
18341
  onPointerDown: (e) => {
@@ -18348,7 +18346,7 @@ function XViewScene({
18348
18346
  title: "Arraste para redimensionar"
18349
18347
  }
18350
18348
  ),
18351
- /* @__PURE__ */ import_react29.default.createElement(
18349
+ /* @__PURE__ */ import_react32.default.createElement(
18352
18350
  DescriptionReadModePanel,
18353
18351
  {
18354
18352
  key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
@@ -18383,7 +18381,7 @@ function XViewScene({
18383
18381
  }
18384
18382
  )
18385
18383
  ),
18386
- ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ import_react29.default.createElement(
18384
+ ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ import_react32.default.createElement(
18387
18385
  CreateAncestryPanel,
18388
18386
  {
18389
18387
  ancestryMode,
@@ -18419,7 +18417,7 @@ function XViewScene({
18419
18417
  onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
18420
18418
  }
18421
18419
  ),
18422
- editingAncestryRel.visible && /* @__PURE__ */ import_react29.default.createElement(
18420
+ editingAncestryRel.visible && /* @__PURE__ */ import_react32.default.createElement(
18423
18421
  AncestryRelationshipPanel,
18424
18422
  {
18425
18423
  data: editingAncestryRel.data,
@@ -18433,7 +18431,7 @@ function XViewScene({
18433
18431
  onUploadFile: upload_file_action
18434
18432
  }
18435
18433
  ),
18436
- detailsNode && detailsNode.is_quest && /* @__PURE__ */ import_react29.default.createElement(
18434
+ detailsNode && detailsNode.is_quest && /* @__PURE__ */ import_react32.default.createElement(
18437
18435
  QuestDetailsPanel,
18438
18436
  {
18439
18437
  node: detailsNode,
@@ -18459,7 +18457,7 @@ function XViewScene({
18459
18457
  onUpdateMilestones: handleUpdateMilestones
18460
18458
  }
18461
18459
  ),
18462
- detailsNode && !detailsNode.is_quest && /* @__PURE__ */ import_react29.default.createElement(
18460
+ detailsNode && !detailsNode.is_quest && /* @__PURE__ */ import_react32.default.createElement(
18463
18461
  NodeDetailsPanel,
18464
18462
  {
18465
18463
  node: detailsNode,
@@ -18491,7 +18489,7 @@ function XViewScene({
18491
18489
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
18492
18490
  }
18493
18491
  ),
18494
- detailsLink && /* @__PURE__ */ import_react29.default.createElement(
18492
+ detailsLink && /* @__PURE__ */ import_react32.default.createElement(
18495
18493
  RelationshipDetailsPanel,
18496
18494
  {
18497
18495
  link: detailsLink,
@@ -18505,7 +18503,7 @@ function XViewScene({
18505
18503
  userRole: userPermissionRole
18506
18504
  }
18507
18505
  ),
18508
- ancestryLinkDetails && /* @__PURE__ */ import_react29.default.createElement(
18506
+ ancestryLinkDetails && /* @__PURE__ */ import_react32.default.createElement(
18509
18507
  AncestryLinkDetailsPanel,
18510
18508
  {
18511
18509
  data: ancestryLinkDetails,
@@ -18516,7 +18514,7 @@ function XViewScene({
18516
18514
  onUploadFile: upload_file_action
18517
18515
  }
18518
18516
  ),
18519
- /* @__PURE__ */ import_react29.default.createElement(
18517
+ /* @__PURE__ */ import_react32.default.createElement(
18520
18518
  "div",
18521
18519
  {
18522
18520
  ref: tooltipRef,
@@ -18543,7 +18541,7 @@ function XViewScene({
18543
18541
  }
18544
18542
  }
18545
18543
  ),
18546
- /* @__PURE__ */ import_react29.default.createElement(
18544
+ /* @__PURE__ */ import_react32.default.createElement(
18547
18545
  ContextMenu,
18548
18546
  {
18549
18547
  data: contextMenu,
@@ -18576,7 +18574,7 @@ function XViewScene({
18576
18574
  onFinishQuest: handleFinishQuestQuick
18577
18575
  }
18578
18576
  ),
18579
- /* @__PURE__ */ import_react29.default.createElement(
18577
+ /* @__PURE__ */ import_react32.default.createElement(
18580
18578
  MultiNodeContextMenu,
18581
18579
  {
18582
18580
  data: multiContextMenu,
@@ -18596,7 +18594,7 @@ function XViewScene({
18596
18594
  )
18597
18595
  }
18598
18596
  ),
18599
- /* @__PURE__ */ import_react29.default.createElement(
18597
+ /* @__PURE__ */ import_react32.default.createElement(
18600
18598
  RelationshipContextMenu,
18601
18599
  {
18602
18600
  data: relationshipMenu,
@@ -18614,14 +18612,14 @@ function XViewScene({
18614
18612
  onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
18615
18613
  }
18616
18614
  ),
18617
- /* @__PURE__ */ import_react29.default.createElement(
18615
+ /* @__PURE__ */ import_react32.default.createElement(
18618
18616
  ImageViewer,
18619
18617
  {
18620
18618
  data: imageViewer,
18621
18619
  onClose: () => setImageViewer({ ...imageViewer, visible: false })
18622
18620
  }
18623
18621
  ),
18624
- /* @__PURE__ */ import_react29.default.createElement(
18622
+ /* @__PURE__ */ import_react32.default.createElement(
18625
18623
  AncestryBoard,
18626
18624
  {
18627
18625
  isOpen: isAncestryBoardOpen,
@@ -18634,7 +18632,7 @@ function XViewScene({
18634
18632
  userRole: userPermissionRole
18635
18633
  }
18636
18634
  ),
18637
- /* @__PURE__ */ import_react29.default.createElement(
18635
+ /* @__PURE__ */ import_react32.default.createElement(
18638
18636
  MilestoneManager,
18639
18637
  {
18640
18638
  isOpen: isMilestoneManagerOpen,
@@ -18643,7 +18641,7 @@ function XViewScene({
18643
18641
  onUpdateMilestones: handleUpdateMilestones
18644
18642
  }
18645
18643
  ),
18646
- /* @__PURE__ */ import_react29.default.createElement(
18644
+ /* @__PURE__ */ import_react32.default.createElement(
18647
18645
  ImportParentFileModal,
18648
18646
  {
18649
18647
  isOpen: isImportModalOpen,
@@ -18656,7 +18654,7 @@ function XViewScene({
18656
18654
  currentAncestries: ancestryDataRef.current || []
18657
18655
  }
18658
18656
  ),
18659
- invalidTargetError && /* @__PURE__ */ import_react29.default.createElement(
18657
+ invalidTargetError && /* @__PURE__ */ import_react32.default.createElement(
18660
18658
  "div",
18661
18659
  {
18662
18660
  className: "ui-overlay",
@@ -18681,13 +18679,13 @@ function XViewScene({
18681
18679
  animation: "fadeInDown 0.5s cubic-bezier(0.16, 1, 0.3, 1)"
18682
18680
  }
18683
18681
  },
18684
- /* @__PURE__ */ import_react29.default.createElement("style", null, `
18682
+ /* @__PURE__ */ import_react32.default.createElement("style", null, `
18685
18683
  @keyframes fadeInDown {
18686
18684
  from { opacity: 0; transform: translate(-50%, -20px); }
18687
18685
  to { opacity: 1; transform: translate(-50%, 0); }
18688
18686
  }
18689
18687
  `),
18690
- /* @__PURE__ */ import_react29.default.createElement(
18688
+ /* @__PURE__ */ import_react32.default.createElement(
18691
18689
  "svg",
18692
18690
  {
18693
18691
  width: "20",
@@ -18699,12 +18697,12 @@ function XViewScene({
18699
18697
  strokeLinecap: "round",
18700
18698
  strokeLinejoin: "round"
18701
18699
  },
18702
- /* @__PURE__ */ import_react29.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
18703
- /* @__PURE__ */ import_react29.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
18704
- /* @__PURE__ */ import_react29.default.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
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" })
18705
18703
  ),
18706
- /* @__PURE__ */ import_react29.default.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
18707
- /* @__PURE__ */ import_react29.default.createElement(
18704
+ /* @__PURE__ */ import_react32.default.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
18705
+ /* @__PURE__ */ import_react32.default.createElement(
18708
18706
  "button",
18709
18707
  {
18710
18708
  onClick: () => setInvalidTargetError(null),
@@ -18734,451 +18732,7 @@ function XViewScene({
18734
18732
  )
18735
18733
  );
18736
18734
  }
18737
-
18738
- // src/x_view_server_logic.js
18739
- async function save_view_data_logic(db_services, filename, data) {
18740
- try {
18741
- const saveResult = await db_services.save_file(filename, data);
18742
- return saveResult;
18743
- } catch (error) {
18744
- console.error("catch (error) em save_view_data_logic:", error);
18745
- return { success: false, error: error.message };
18746
- }
18747
- }
18748
- async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
18749
- var _a, _b;
18750
- try {
18751
- if (!session || !session.user) {
18752
- return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
18753
- }
18754
- const membershipCheck = await db_services.check_membership(owner_id, type, scene_config, session.user.id);
18755
- const isFullMember = membershipCheck.success && membershipCheck.isValidMember;
18756
- if (!isFullMember && !focusNodeId && !focusAncestryId) {
18757
- return { success: false, error: "Acesso Negado: Voc\xEA n\xE3o possui permiss\xE3o para acessar este cen\xE1rio." };
18758
- }
18759
- const sceneResponse = await db_services.get_file(`x_view_scenes/${owner_id}/${scene_config}`);
18760
- if (!sceneResponse || !sceneResponse.success) {
18761
- console.error("Falha ao buscar dados da cena:", sceneResponse == null ? void 0 : sceneResponse.error);
18762
- return { success: false, error: `N\xE3o foi poss\xEDvel carregar o arquivo da cena: ${scene_config}` };
18763
- }
18764
- const sceneData = sceneResponse.data;
18765
- const parentDbObjects = sceneData.parent_dbs || [];
18766
- if (type && type.toLowerCase().includes("database")) {
18767
- const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
18768
- if (!selfExists) {
18769
- parentDbObjects.push({ db_id: scene_config, owner_id });
18770
- }
18771
- }
18772
- const parentResponsesPromises = parentDbObjects.map(
18773
- (db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
18774
- );
18775
- const parentResponsesResults = await Promise.allSettled(parentResponsesPromises);
18776
- const parentData = {};
18777
- for (let i = 0; i < parentResponsesResults.length; i++) {
18778
- const result = parentResponsesResults[i];
18779
- const db_info = parentDbObjects[i];
18780
- if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
18781
- parentData[db_info.db_id] = result.value.data;
18782
- } else {
18783
- console.warn(
18784
- `Arquivo pai n\xE3o carregado: ${db_info.db_id}. Pode ter sido deletado.`,
18785
- result.status === "rejected" ? result.reason : (_b = result.value) == null ? void 0 : _b.error
18786
- );
18787
- }
18788
- }
18789
- if (type && type.toLowerCase() === "view") {
18790
- parentData[scene_config] = {
18791
- dataset_name: "Quests Internas (View)",
18792
- nodes: sceneData.quest_nodes || [],
18793
- links: sceneData.quest_links || []
18794
- };
18795
- }
18796
- const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
18797
- const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
18798
- const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
18799
- const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
18800
- const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
18801
- var _a2, _b2;
18802
- const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
18803
- if (nodeTypes.includes("quest")) {
18804
- const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
18805
- if (dbQuestNode) {
18806
- return { ...sceneNode, ...dbQuestNode };
18807
- }
18808
- return sceneNode;
18809
- }
18810
- const dbNode = parentNodeMap.get(String(sceneNode.id));
18811
- if (dbNode) {
18812
- return { ...sceneNode, ...dbNode };
18813
- }
18814
- return null;
18815
- }).filter(Boolean);
18816
- const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
18817
- const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
18818
- const linkExistsInParent = parentLinkMap.has(`${sceneLink.source}-${sceneLink.target}`);
18819
- const nodesAreValidForScene = validNodeIdsInScene.has(String(sceneLink.source)) && validNodeIdsInScene.has(String(sceneLink.target));
18820
- return linkExistsInParent && nodesAreValidForScene;
18821
- }).map((sceneLink) => parentLinkMap.get(`${sceneLink.source}-${sceneLink.target}`));
18822
- const validatedSceneData = {
18823
- ...sceneData,
18824
- nodes: validatedNodes,
18825
- links: validatedLinks
18826
- };
18827
- const ancestryFilePaths = [];
18828
- ancestryFilePaths.push({
18829
- path: `x_view_ancestry/${owner_id}/${scene_config}`,
18830
- source_id: scene_config,
18831
- owner_id,
18832
- isSceneFile: true
18833
- });
18834
- parentDbObjects.forEach((db_info) => {
18835
- ancestryFilePaths.push({
18836
- path: `x_view_ancestry/${db_info.owner_id}/${db_info.db_id}`,
18837
- source_id: db_info.db_id,
18838
- owner_id: db_info.owner_id,
18839
- isSceneFile: false
18840
- });
18841
- });
18842
- const ancestryPromises = ancestryFilePaths.map((file) => db_services.get_file(file.path));
18843
- const ancestryResults = await Promise.allSettled(ancestryPromises);
18844
- const ancestriesFromSceneFile = [];
18845
- const ancestriesFromDbFiles = [];
18846
- ancestryResults.forEach((result, index) => {
18847
- var _a2;
18848
- const fileInfo = ancestryFilePaths[index];
18849
- if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
18850
- const ancestriesFromFile = result.value.data.map((ancestry) => {
18851
- const existingSource = ancestry._source_file_id;
18852
- const existingOwner = ancestry._source_owner_id;
18853
- const isImportedItem = existingSource && existingSource !== fileInfo.source_id;
18854
- return {
18855
- ...ancestry,
18856
- _source_file_id: isImportedItem ? existingSource : fileInfo.source_id,
18857
- _source_owner_id: isImportedItem ? existingOwner : fileInfo.owner_id
18858
- };
18859
- });
18860
- if (fileInfo.isSceneFile) {
18861
- ancestriesFromSceneFile.push(...ancestriesFromFile);
18862
- } else {
18863
- ancestriesFromDbFiles.push(...ancestriesFromFile);
18864
- }
18865
- }
18866
- });
18867
- const ancestryMap = /* @__PURE__ */ new Map();
18868
- ancestriesFromDbFiles.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
18869
- ancestriesFromSceneFile.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
18870
- let ancestryData = Array.from(ancestryMap.values());
18871
- const externalSourcesToRefresh = /* @__PURE__ */ new Map();
18872
- ancestryData.forEach((anc) => {
18873
- const targetSourceId = anc._source_file_id || anc._imported_from_view_id;
18874
- const targetOwnerId = anc._source_owner_id || anc._imported_from_view_owner_id;
18875
- if (targetSourceId && targetSourceId !== scene_config && targetOwnerId) {
18876
- const isAlreadyLoadedAsParent = parentDbObjects.some((db) => String(db.db_id) === String(targetSourceId));
18877
- if (!isAlreadyLoadedAsParent) {
18878
- const key = `${targetOwnerId}/${targetSourceId}`;
18879
- externalSourcesToRefresh.set(key, {
18880
- owner_id: targetOwnerId,
18881
- source_id: targetSourceId,
18882
- key
18883
- });
18884
- }
18885
- }
18886
- });
18887
- const successfullyFetchedSources = /* @__PURE__ */ new Set();
18888
- const failedSources = /* @__PURE__ */ new Set();
18889
- if (externalSourcesToRefresh.size > 0) {
18890
- const refreshPromises = Array.from(externalSourcesToRefresh.values()).map(
18891
- (src) => db_services.get_file(`x_view_ancestry/${src.owner_id}/${src.source_id}`).then((res) => ({ ...res, _meta_key: src.key }))
18892
- );
18893
- const refreshResults = await Promise.allSettled(refreshPromises);
18894
- const freshAncestryMap = /* @__PURE__ */ new Map();
18895
- refreshResults.forEach((result) => {
18896
- var _a2, _b2;
18897
- if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
18898
- successfullyFetchedSources.add(result.value._meta_key);
18899
- result.value.data.forEach((freshAnc) => {
18900
- if (!freshAnc.is_private) {
18901
- freshAncestryMap.set(String(freshAnc.ancestry_id), freshAnc);
18902
- }
18903
- });
18904
- } else if (result.status === "fulfilled" && !((_b2 = result.value) == null ? void 0 : _b2.success)) {
18905
- failedSources.add(result.value._meta_key);
18906
- }
18907
- });
18908
- ancestryData = ancestryData.filter((localAnc) => {
18909
- const targetSourceId = localAnc._source_file_id || localAnc._imported_from_view_id;
18910
- const targetOwnerId = localAnc._source_owner_id || localAnc._imported_from_view_owner_id;
18911
- if (!targetSourceId || targetSourceId === scene_config) return true;
18912
- const key = `${targetOwnerId}/${targetSourceId}`;
18913
- if (failedSources.has(key)) {
18914
- return false;
18915
- }
18916
- if (externalSourcesToRefresh.has(key) && successfullyFetchedSources.has(key)) {
18917
- const stillExists = freshAncestryMap.has(String(localAnc.ancestry_id));
18918
- return stillExists;
18919
- }
18920
- return true;
18921
- }).map((localAnc) => {
18922
- const freshVersion = freshAncestryMap.get(String(localAnc.ancestry_id));
18923
- if (freshVersion) {
18924
- return {
18925
- ...freshVersion,
18926
- _imported_from_view_id: localAnc._imported_from_view_id,
18927
- _imported_from_view_owner_id: localAnc._imported_from_view_owner_id,
18928
- _origin_db_ids: localAnc._origin_db_ids,
18929
- _source_file_id: localAnc._source_file_id,
18930
- _source_owner_id: localAnc._source_owner_id
18931
- };
18932
- }
18933
- return localAnc;
18934
- });
18935
- }
18936
- const ancestryFilePath = `x_view_ancestry/${owner_id}/${scene_config}`;
18937
- const parentNodeIds = new Set(allNodes.map((node) => String(node.id)));
18938
- const pruneTree = (node) => {
18939
- if (!node) return null;
18940
- if (node.is_section) {
18941
- const validChildren2 = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
18942
- return { ...node, children: validChildren2 };
18943
- }
18944
- if (!parentNodeIds.has(String(node.node_id))) {
18945
- return null;
18946
- }
18947
- const validChildren = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
18948
- let validBranches = [];
18949
- if (node.parallel_branches) {
18950
- validBranches = node.parallel_branches.map((branch) => ({
18951
- ...branch,
18952
- tree: pruneTree(branch.tree)
18953
- })).filter((b) => b.tree !== null);
18954
- }
18955
- return {
18956
- ...node,
18957
- children: validChildren,
18958
- parallel_branches: validBranches
18959
- };
18960
- };
18961
- const originalAncestryDataString = JSON.stringify(Array.from(ancestryMap.values()));
18962
- const cleanedAncestryData = ancestryData.map((ancestry) => {
18963
- if (!parentNodeIds.has(String(ancestry.ancestral_node))) return null;
18964
- const cleanedTree = pruneTree(ancestry.tree);
18965
- if (!cleanedTree) return null;
18966
- let cleanedAbstraction = null;
18967
- if (ancestry.abstraction_tree) {
18968
- cleanedAbstraction = pruneTree(ancestry.abstraction_tree);
18969
- }
18970
- return {
18971
- ...ancestry,
18972
- tree: cleanedTree,
18973
- abstraction_tree: cleanedAbstraction
18974
- };
18975
- }).filter(Boolean);
18976
- if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
18977
- ancestryData = cleanedAncestryData;
18978
- try {
18979
- await db_services.save_file(ancestryFilePath, ancestryData);
18980
- } catch (saveError) {
18981
- console.error("Falha ao salvar o arquivo de ancestralidade da cena atualizado:", saveError);
18982
- }
18983
- }
18984
- if (!isFullMember) {
18985
- const requiredNodeIds = /* @__PURE__ */ new Set();
18986
- const requiredAncestryIds = /* @__PURE__ */ new Set();
18987
- if (focusNodeId) requiredNodeIds.add(String(focusNodeId));
18988
- if (focusAncestryId) requiredAncestryIds.add(String(focusAncestryId));
18989
- const allNodesFromDb = Object.values(parentData).flatMap((db) => db.nodes || []);
18990
- const extractDependenciesFromText = (text) => {
18991
- if (!text) return;
18992
- const mentionRegex = /\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g;
18993
- const refRegex = /\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g;
18994
- let match;
18995
- while ((match = mentionRegex.exec(text)) !== null) {
18996
- requiredNodeIds.add(match[1]);
18997
- }
18998
- while ((match = refRegex.exec(text)) !== null) {
18999
- if (match[1] === "node") requiredNodeIds.add(match[2]);
19000
- if (match[1] === "ancestry") requiredAncestryIds.add(match[2]);
19001
- }
19002
- };
19003
- const extractTreeDependencies = (treeItem) => {
19004
- var _a2;
19005
- if (!treeItem) return;
19006
- if (treeItem.node_id) requiredNodeIds.add(String(treeItem.node_id));
19007
- if ((_a2 = treeItem.node) == null ? void 0 : _a2.id) requiredNodeIds.add(String(treeItem.node.id));
19008
- if (treeItem.children) {
19009
- treeItem.children.forEach(extractTreeDependencies);
19010
- }
19011
- if (treeItem.parallel_branches) {
19012
- treeItem.parallel_branches.forEach((branch) => {
19013
- if (branch.linked_ancestry_id) {
19014
- requiredAncestryIds.add(String(branch.linked_ancestry_id));
19015
- }
19016
- if (branch.description) extractDependenciesFromText(branch.description);
19017
- if (branch.description_sections) {
19018
- branch.description_sections.forEach((s) => extractDependenciesFromText(s.content));
19019
- }
19020
- extractTreeDependencies(branch.tree);
19021
- });
19022
- }
19023
- };
19024
- let previousSize;
19025
- do {
19026
- previousSize = requiredNodeIds.size + requiredAncestryIds.size;
19027
- requiredAncestryIds.forEach((ancId) => {
19028
- const anc = ancestryData.find((a) => String(a.ancestry_id) === ancId);
19029
- if (anc && !anc.is_private) {
19030
- if (anc.description) extractDependenciesFromText(anc.description);
19031
- if (anc.description_sections) {
19032
- anc.description_sections.forEach((s) => extractDependenciesFromText(s.content));
19033
- }
19034
- extractTreeDependencies(anc.tree);
19035
- extractTreeDependencies(anc.abstraction_tree);
19036
- }
19037
- });
19038
- requiredNodeIds.forEach((nodeId) => {
19039
- const node = allNodesFromDb.find((n) => String(n.id) === nodeId);
19040
- if (node) {
19041
- if (node.description) extractDependenciesFromText(node.description);
19042
- if (node.description_sections) {
19043
- node.description_sections.forEach((s) => extractDependenciesFromText(s.content));
19044
- }
19045
- }
19046
- });
19047
- } while (requiredNodeIds.size + requiredAncestryIds.size > previousSize);
19048
- const restrictedSceneData = { ...validatedSceneData, nodes: [], links: [] };
19049
- const restrictedParentData = {};
19050
- const restrictedAncestryData = ancestryData.filter((a) => requiredAncestryIds.has(String(a.ancestry_id)) && !a.is_private);
19051
- for (const [dbId, dbContent] of Object.entries(parentData)) {
19052
- const filteredNodes = (dbContent.nodes || []).filter((n) => requiredNodeIds.has(String(n.id)));
19053
- if (filteredNodes.length > 0) {
19054
- restrictedParentData[dbId] = { ...dbContent, nodes: filteredNodes, links: [] };
19055
- }
19056
- }
19057
- if (focusNodeId) {
19058
- const mainNode = allNodesFromDb.find((n) => String(n.id) === String(focusNodeId));
19059
- if (mainNode) {
19060
- restrictedSceneData.nodes = [mainNode];
19061
- }
19062
- }
19063
- return {
19064
- success: true,
19065
- data: {
19066
- scene: restrictedSceneData,
19067
- parent: restrictedParentData,
19068
- ancestry: restrictedAncestryData
19069
- }
19070
- };
19071
- }
19072
- return {
19073
- success: true,
19074
- data: { scene: validatedSceneData, parent: parentData, ancestry: ancestryData }
19075
- };
19076
- } catch (error) {
19077
- console.error("Erro em get_scene_view_data_logic:", error);
19078
- return { success: false, error: error.message };
19079
- }
19080
- }
19081
- async function import_parent_file_modal_get_logic(db_services, session) {
19082
- try {
19083
- const call_firestore_get_x_view_data = await db_services.get_firestore_data(session);
19084
- const x_view_databases = call_firestore_get_x_view_data.data.sub_collections.x_view_databases || [];
19085
- const x_views = call_firestore_get_x_view_data.data.sub_collections.x_views || [];
19086
- return {
19087
- success: true,
19088
- data: {
19089
- databases: x_view_databases,
19090
- views: x_views
19091
- }
19092
- };
19093
- } catch (error) {
19094
- console.error("catch (error) em import_parent_file_modal_get_logic:", error);
19095
- return { success: false, error: error.message };
19096
- }
19097
- }
19098
- async function get_single_parent_file_logic(db_services, file_id, session) {
19099
- try {
19100
- const call_GCP_cloud_storage_get_file = await db_services.get_file(`x_view_dbs/${session.user.id}/${file_id}`);
19101
- return call_GCP_cloud_storage_get_file;
19102
- } catch (error) {
19103
- console.error("catch (error) em get_single_parent_file_logic:", error);
19104
- return { success: false, error: error.message };
19105
- }
19106
- }
19107
- async function x_view_add_new_parent_file_to_scene_at_firebase(file_id, session, new_parent, db_services) {
19108
- try {
19109
- const update_data = {
19110
- scene_id: file_id,
19111
- new_parent,
19112
- session
19113
- };
19114
- const call_firestore_add_new_parent_file_to_scene_at_firebase = await db_services.add_new_parent_file_to_scene_at_firebase(update_data);
19115
- return call_firestore_add_new_parent_file_to_scene_at_firebase;
19116
- } catch (error) {
19117
- console.error("catch (error) em get_single_parent_file_logic:", error);
19118
- return { success: false, error: error.message };
19119
- }
19120
- }
19121
- async function get_ancestry_file_logic(db_services, file_id, owner_id) {
19122
- try {
19123
- const path = `x_view_ancestry/${owner_id}/${file_id}`;
19124
- const call_GCP_cloud_storage_get_file = await db_services.get_file(path);
19125
- return call_GCP_cloud_storage_get_file;
19126
- } catch (error) {
19127
- console.error("catch (error) em get_ancestry_file_logic:", error);
19128
- return { success: false, error: error.message };
19129
- }
19130
- }
19131
- async function save_ancestry_board_logic(db_services, scene_id, type, groups, session, owner_id) {
19132
- try {
19133
- const targetOwnerId = owner_id || session.user.id;
19134
- return await db_services.save_ancestry_board(session, scene_id, type, groups, targetOwnerId);
19135
- } catch (error) {
19136
- console.error("Erro em save_ancestry_board_logic:", error);
19137
- return { success: false, error: error.message };
19138
- }
19139
- }
19140
- async function get_ancestry_board_logic(db_services, scene_id, type, session, owner_id) {
19141
- try {
19142
- const targetOwnerId = owner_id || session.user.id;
19143
- return await db_services.get_ancestry_board(session, scene_id, type, targetOwnerId);
19144
- } catch (error) {
19145
- console.error("Erro em get_ancestry_board_logic:", error);
19146
- return { success: false, error: error.message };
19147
- }
19148
- }
19149
- async function delete_uploaded_file_logic(db_services, fileUrl) {
19150
- try {
19151
- if (db_services.delete_public_file) {
19152
- return await db_services.delete_public_file(fileUrl);
19153
- }
19154
- return { success: false, error: "Servi\xE7o de dele\xE7\xE3o n\xE3o configurado." };
19155
- } catch (error) {
19156
- console.error("Erro em delete_uploaded_file_logic:", error);
19157
- return { success: false, error: error.message };
19158
- }
19159
- }
19160
- async function get_view_members_logic(db_services, ownerId, type, itemId) {
19161
- try {
19162
- if (!db_services.get_view_members) {
19163
- return { success: false, error: "Servi\xE7o de busca de membros n\xE3o configurado." };
19164
- }
19165
- return await db_services.get_view_members(ownerId, type, itemId);
19166
- } catch (error) {
19167
- console.error("Erro em get_view_members_logic:", error);
19168
- return { success: false, error: error.message };
19169
- }
19170
- }
19171
18735
  // Annotate the CommonJS export names for ESM import in node:
19172
18736
  0 && (module.exports = {
19173
- XViewScene,
19174
- delete_uploaded_file_logic,
19175
- get_ancestry_board_logic,
19176
- get_ancestry_file_logic,
19177
- get_scene_view_data_logic,
19178
- get_single_parent_file_logic,
19179
- get_view_members_logic,
19180
- import_parent_file_modal_get_logic,
19181
- save_ancestry_board_logic,
19182
- save_view_data_logic,
19183
- x_view_add_new_parent_file_to_scene_at_firebase
18737
+ XViewScene
19184
18738
  });