@lv-x-software-house/x_view 1.2.5-dev.31 → 1.2.5-dev.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +136 -19
  2. package/dist/index.mjs +141 -24
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9724,12 +9724,16 @@ var EVENT_ICONS = {
9724
9724
  function QuestTimeline({
9725
9725
  timeline = [],
9726
9726
  viewMembers = [],
9727
- onOpenImageViewer
9727
+ onOpenImageViewer,
9728
+ onAddNote,
9729
+ // Nova prop para adicionar nota a uma etapa específica
9730
+ canEdit = true
9728
9731
  }) {
9729
9732
  const sortedTimeline = [...timeline].sort((a, b) => b.timestamp - a.timestamp);
9730
9733
  const getMemberName = (userId) => {
9731
- const member = viewMembers.find((m) => m.id === userId);
9732
- return (member == null ? void 0 : member.name) || (member == null ? void 0 : member.email) || "Sistema";
9734
+ if (!userId) return "Sistema";
9735
+ const member = viewMembers.find((m) => String(m.id) === String(userId));
9736
+ return (member == null ? void 0 : member.name) || (member == null ? void 0 : member.email) || userId;
9733
9737
  };
9734
9738
  const formatDate = (timestamp) => {
9735
9739
  const date = new Date(timestamp);
@@ -9743,11 +9747,23 @@ function QuestTimeline({
9743
9747
  if (timeline.length === 0) {
9744
9748
  return /* @__PURE__ */ import_react19.default.createElement("div", { className: "py-6 flex flex-col items-center justify-center gap-2 border border-white/5 bg-white/5 rounded-xl" }, /* @__PURE__ */ import_react19.default.createElement(import_fi17.FiAlertCircle, { className: "text-slate-600", size: 16 }), /* @__PURE__ */ import_react19.default.createElement("p", { className: "text-[10px] text-slate-500 font-light uppercase tracking-widest" }, "Nenhum hist\xF3rico dispon\xEDvel"));
9745
9749
  }
9746
- return /* @__PURE__ */ import_react19.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ import_react19.default.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider flex items-center gap-2" }, "Hist\xF3rico (Timeline)"), /* @__PURE__ */ import_react19.default.createElement("div", { className: "relative pl-6 space-y-6 before:content-[''] before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-[2px] before:bg-white/5" }, sortedTimeline.map((event, index) => {
9750
+ return /* @__PURE__ */ import_react19.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ import_react19.default.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider flex items-center gap-2" }, "Hist\xF3rico (Timeline)"), /* @__PURE__ */ import_react19.default.createElement("div", { className: "relative pl-10 space-y-6 before:content-[''] before:absolute before:left-[21px] before:top-2 before:bottom-2 before:w-[2px] before:bg-white/5" }, sortedTimeline.map((event, index) => {
9747
9751
  const config = EVENT_ICONS[event.type] || EVENT_ICONS.default;
9748
9752
  const Icon = config.icon;
9749
9753
  const actorName = getMemberName(event.actorId);
9750
- return /* @__PURE__ */ import_react19.default.createElement("div", { key: index, className: "relative animate-in fade-in slide-in-from-left-2 duration-300", style: { animationDelay: `${index * 50}ms` } }, /* @__PURE__ */ import_react19.default.createElement("div", { className: `absolute -left-[27px] top-0 w-8 h-8 rounded-full ${config.bg} flex items-center justify-center ring-4 ring-slate-950 border border-white/5` }, /* @__PURE__ */ import_react19.default.createElement(Icon, { className: config.iconColor || config.color, size: 14 })), /* @__PURE__ */ import_react19.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center justify-between gap-4" }, /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-xs font-semibold text-slate-200" }, actorName), /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-[10px] text-slate-500 tabular-nums" }, formatDate(event.timestamp))), /* @__PURE__ */ import_react19.default.createElement("p", { className: "text-sm text-slate-400 leading-relaxed" }, event.description), (event.from_status || event.to_status) && /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-1.5 py-1 px-2 rounded-md bg-white/5 border border-white/5 w-fit mt-2" }, /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-[10px] text-slate-500" }, event.from_status || "?"), /* @__PURE__ */ import_react19.default.createElement(import_fi17.FiArrowRight, { size: 10, className: "text-slate-600" }), /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-[10px] text-indigo-300 font-bold" }, event.to_status || "?")), event.metadata && Object.keys(event.metadata).length > 0 && /* @__PURE__ */ import_react19.default.createElement("div", { className: "mt-2 text-[10px] grid grid-cols-2 gap-2 p-2 bg-slate-900/50 rounded border border-white/5" }, Object.entries(event.metadata).map(([key, value]) => /* @__PURE__ */ import_react19.default.createElement("div", { key, className: "flex flex-col gap-0.5" }, /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-slate-500 capitalize" }, key.replace(/_/g, " ")), /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-slate-300 truncate font-mono" }, typeof value === "string" ? value : JSON.stringify(value))))), event.links && event.links.length > 0 && /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-wrap gap-2 mt-2" }, event.links.map((link, lIdx) => /* @__PURE__ */ import_react19.default.createElement(
9754
+ return /* @__PURE__ */ import_react19.default.createElement("div", { key: event.id || index, className: "relative animate-in fade-in slide-in-from-left-2 duration-300", style: { animationDelay: `${index * 50}ms` } }, /* @__PURE__ */ import_react19.default.createElement("div", { className: `absolute -left-[35px] top-0 w-8 h-8 rounded-full ${config.bg} flex items-center justify-center ring-4 ring-slate-950 border border-white/5` }, /* @__PURE__ */ import_react19.default.createElement(Icon, { className: config.iconColor || config.color, size: 14 })), /* @__PURE__ */ import_react19.default.createElement("div", { className: "group space-y-1" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center justify-between gap-4" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-xs font-semibold text-slate-200" }, actorName), canEdit && onAddNote && /* @__PURE__ */ import_react19.default.createElement(
9755
+ "button",
9756
+ {
9757
+ onClick: () => onAddNote(event),
9758
+ className: "opacity-0 group-hover:opacity-100 p-1 rounded-md hover:bg-white/5 text-slate-500 hover:text-indigo-400 transition-all",
9759
+ title: "Adicionar detalhe/anexo a esta etapa"
9760
+ },
9761
+ /* @__PURE__ */ import_react19.default.createElement(import_fi17.FiPlusCircle, { size: 12 })
9762
+ )), /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-[10px] text-slate-500 tabular-nums" }, formatDate(event.timestamp))), /* @__PURE__ */ import_react19.default.createElement("p", { className: "text-sm text-slate-400 leading-relaxed" }, event.description), event.notes && /* @__PURE__ */ import_react19.default.createElement("div", { className: "mt-1 py-1 px-2 rounded bg-indigo-500/5 border-l-2 border-indigo-500/30" }, /* @__PURE__ */ import_react19.default.createElement("p", { className: "text-[11px] text-slate-300 italic whitespace-pre-wrap" }, event.notes)), (event.from_status || event.to_status) && /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-1.5 py-1 px-2 rounded-md bg-white/5 border border-white/5 w-fit mt-2" }, /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-[10px] text-slate-500" }, event.from_status || "?"), /* @__PURE__ */ import_react19.default.createElement(import_fi17.FiArrowRight, { size: 10, className: "text-slate-600" }), /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-[10px] text-indigo-300 font-bold" }, event.to_status || "?")), event.metadata && Object.keys(event.metadata).length > 0 && /* @__PURE__ */ import_react19.default.createElement("div", { className: "mt-2 text-[10px] grid grid-cols-2 gap-2 p-2 bg-slate-900/50 rounded border border-white/5" }, Object.entries(event.metadata).map(([key, value]) => {
9763
+ const isAssigneeId = key.toLowerCase().includes("assignee_id") || key.toLowerCase().includes("respons\xE1vel") || key.toLowerCase().includes("assignee id");
9764
+ const displayValue = isAssigneeId && typeof value === "string" ? getMemberName(value) : typeof value === "string" ? value : JSON.stringify(value);
9765
+ return /* @__PURE__ */ import_react19.default.createElement("div", { key, className: "flex flex-col gap-0.5" }, /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-slate-500 capitalize" }, key.replace(/_/g, " ")), /* @__PURE__ */ import_react19.default.createElement("span", { className: `${isAssigneeId ? "text-indigo-300 font-medium" : "text-slate-300"} truncate font-mono` }, displayValue));
9766
+ })), event.links && event.links.length > 0 && /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-wrap gap-2 mt-2" }, event.links.map((link, lIdx) => /* @__PURE__ */ import_react19.default.createElement(
9751
9767
  "a",
9752
9768
  {
9753
9769
  key: lIdx,
@@ -9764,10 +9780,10 @@ function QuestTimeline({
9764
9780
  key: iIdx,
9765
9781
  type: "button",
9766
9782
  onClick: () => onOpenImageViewer == null ? void 0 : onOpenImageViewer(event.images, iIdx),
9767
- className: "relative w-12 h-12 rounded border border-white/10 overflow-hidden hover:border-sky-500/50 transition-colors group"
9783
+ className: "relative w-12 h-12 rounded border border-white/10 overflow-hidden hover:border-sky-500/50 transition-colors group/img"
9768
9784
  },
9769
9785
  /* @__PURE__ */ import_react19.default.createElement("img", { src: img.value, alt: img.name, className: "w-full h-full object-cover" }),
9770
- /* @__PURE__ */ import_react19.default.createElement("div", { className: "absolute inset-0 bg-slate-900/40 opacity-0 group-hover:opacity-100 flex items-center justify-center transition-opacity" }, /* @__PURE__ */ import_react19.default.createElement(import_fi17.FiSearch, { size: 12, className: "text-white" }))
9786
+ /* @__PURE__ */ import_react19.default.createElement("div", { className: "absolute inset-0 bg-slate-900/40 opacity-0 group-hover/img:opacity-100 flex items-center justify-center transition-opacity" }, /* @__PURE__ */ import_react19.default.createElement(import_fi17.FiSearch, { size: 12, className: "text-white" }))
9771
9787
  )))));
9772
9788
  })));
9773
9789
  }
@@ -9830,7 +9846,11 @@ function QuestDetailsPanel({
9830
9846
  const [isLinkCopied, setIsLinkCopied] = (0, import_react20.useState)(false);
9831
9847
  const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react20.useState)(false);
9832
9848
  const [noteText, setNoteText] = (0, import_react20.useState)("");
9849
+ const [noteLinks, setNoteLinks] = (0, import_react20.useState)([]);
9850
+ const [noteImages, setNoteImages] = (0, import_react20.useState)([]);
9833
9851
  const [isNoteFormOpen, setIsNoteFormOpen] = (0, import_react20.useState)(false);
9852
+ const [editingEntryId, setEditingEntryId] = (0, import_react20.useState)(null);
9853
+ const [editingEntryLabel, setEditingEntryLabel] = (0, import_react20.useState)("");
9834
9854
  const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
9835
9855
  const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
9836
9856
  initialWidth: isReadMode ? 700 : 440,
@@ -9962,11 +9982,30 @@ function QuestDetailsPanel({
9962
9982
  }
9963
9983
  };
9964
9984
  const handleAddTimelineNote = async () => {
9965
- if (!noteText.trim() || isSaving) return;
9985
+ if (!noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving) return;
9966
9986
  setIsSaving(true);
9967
9987
  const actorId = (currentUser == null ? void 0 : currentUser.id) || "unknown";
9968
- const newEntry = createTimelineEntry(actorId, noteText, "comment");
9969
- const updatedTimeline = [...timeline, newEntry];
9988
+ let updatedTimeline;
9989
+ if (editingEntryId) {
9990
+ updatedTimeline = timeline.map((entry) => {
9991
+ if (entry.id === editingEntryId) {
9992
+ return {
9993
+ ...entry,
9994
+ notes: noteText.trim() ? entry.notes ? `${entry.notes}
9995
+ ${noteText}` : noteText : entry.notes,
9996
+ links: [...entry.links || [], ...noteLinks],
9997
+ images: [...entry.images || [], ...noteImages]
9998
+ };
9999
+ }
10000
+ return entry;
10001
+ });
10002
+ } else {
10003
+ const newEntry = createTimelineEntry(actorId, noteText, "comment", {
10004
+ links: noteLinks,
10005
+ images: noteImages
10006
+ });
10007
+ updatedTimeline = [...timeline, newEntry];
10008
+ }
9970
10009
  try {
9971
10010
  const nodeToSave = {
9972
10011
  ...node,
@@ -9976,13 +10015,47 @@ function QuestDetailsPanel({
9976
10015
  setTimeline(updatedTimeline);
9977
10016
  onDataUpdate(nodeToSave);
9978
10017
  setNoteText("");
10018
+ setNoteLinks([]);
10019
+ setNoteImages([]);
9979
10020
  setIsNoteFormOpen(false);
10021
+ setEditingEntryId(null);
10022
+ setEditingEntryLabel("");
9980
10023
  } catch (error) {
9981
10024
  console.error("Erro ao adicionar nota:", error);
9982
10025
  } finally {
9983
10026
  setIsSaving(false);
9984
10027
  }
9985
10028
  };
10029
+ const handleOpenNoteForEntry = (entry) => {
10030
+ setEditingEntryId(entry.id);
10031
+ setEditingEntryLabel(entry.description);
10032
+ setNoteText("");
10033
+ setNoteLinks([]);
10034
+ setNoteImages([]);
10035
+ setIsNoteFormOpen(true);
10036
+ setTimeout(() => {
10037
+ const form = document.getElementById("quest-note-form");
10038
+ form == null ? void 0 : form.scrollIntoView({ behavior: "smooth", block: "center" });
10039
+ }, 100);
10040
+ };
10041
+ const addLinkToNote = () => {
10042
+ setNoteLinks([...noteLinks, { id: v4_default(), name: "", value: "" }]);
10043
+ };
10044
+ const removeLinkFromNote = (id) => {
10045
+ setNoteLinks(noteLinks.filter((l) => l.id !== id));
10046
+ };
10047
+ const updateLinkInNote = (id, field, val) => {
10048
+ setNoteLinks(noteLinks.map((l) => l.id === id ? { ...l, [field]: val } : l));
10049
+ };
10050
+ const addImageToNote = () => {
10051
+ setNoteImages([...noteImages, { id: v4_default(), name: "Image", value: "" }]);
10052
+ };
10053
+ const removeImageFromNote = (id) => {
10054
+ setNoteImages(noteImages.filter((img) => img.id !== id));
10055
+ };
10056
+ const updateImageInNote = (id, val) => {
10057
+ setNoteImages(noteImages.map((img) => img.id === id ? { ...img, value: val } : img));
10058
+ };
9986
10059
  const handleStatusChange = (newStatus) => {
9987
10060
  setStatus(newStatus);
9988
10061
  const newColor = QUEST_STATUS_COLORS3[newStatus];
@@ -10326,34 +10399,78 @@ function QuestDetailsPanel({
10326
10399
  "button",
10327
10400
  {
10328
10401
  type: "button",
10329
- onClick: () => setIsNoteFormOpen(!isNoteFormOpen),
10402
+ onClick: () => {
10403
+ if (isNoteFormOpen && editingEntryId) {
10404
+ setEditingEntryId(null);
10405
+ setEditingEntryLabel("");
10406
+ setNoteText("");
10407
+ setNoteLinks([]);
10408
+ setNoteImages([]);
10409
+ } else {
10410
+ setIsNoteFormOpen(!isNoteFormOpen);
10411
+ setEditingEntryId(null);
10412
+ setEditingEntryLabel("");
10413
+ }
10414
+ },
10330
10415
  className: "flex items-center gap-1.5 px-2 py-1 text-[10px] rounded-md bg-white/5 hover:bg-white/10 border border-white/10 transition-colors text-slate-300"
10331
10416
  },
10332
- isNoteFormOpen ? /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiX, { size: 12 }) : /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiPlus, { size: 12 }),
10333
- isNoteFormOpen ? "Cancelar" : "Nova Nota"
10334
- )), isNoteFormOpen && /* @__PURE__ */ import_react20.default.createElement("div", { className: "mb-6 p-4 rounded-xl bg-white/5 border border-white/5 space-y-3 animate-in fade-in slide-in-from-top-2" }, /* @__PURE__ */ import_react20.default.createElement(
10417
+ isNoteFormOpen && !editingEntryId ? /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiX, { size: 12 }) : /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiPlus, { size: 12 }),
10418
+ isNoteFormOpen && !editingEntryId ? "Cancelar" : "Nova Nota"
10419
+ )), isNoteFormOpen && /* @__PURE__ */ import_react20.default.createElement("div", { id: "quest-note-form", className: "mb-6 p-4 rounded-xl bg-white/5 border border-white/5 space-y-3 animate-in fade-in slide-in-from-top-2 border-l-4 border-l-indigo-500/40" }, editingEntryId && /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between mb-2 pb-2 border-b border-white/5" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react20.default.createElement("span", { className: "text-[10px] text-indigo-400 font-bold uppercase tracking-wider" }, "Adicionando \xE0 etapa:"), /* @__PURE__ */ import_react20.default.createElement("span", { className: "text-xs text-slate-300 italic truncate max-w-[250px]" }, editingEntryLabel)), /* @__PURE__ */ import_react20.default.createElement("button", { type: "button", onClick: () => {
10420
+ setIsNoteFormOpen(false);
10421
+ setEditingEntryId(null);
10422
+ }, className: "text-slate-500 hover:text-white" }, /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiX, { size: 14 }))), /* @__PURE__ */ import_react20.default.createElement(
10335
10423
  "textarea",
10336
10424
  {
10337
10425
  value: noteText,
10338
10426
  onChange: (e) => setNoteText(e.target.value),
10339
- placeholder: "Escreva uma observa\xE7\xE3o no hist\xF3rico...",
10427
+ placeholder: editingEntryId ? "Adicione uma observa\xE7\xE3o a esta etapa..." : "Escreva uma observa\xE7\xE3o no hist\xF3rico...",
10340
10428
  className: "w-full bg-slate-900/50 p-3 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-500/50 min-h-[80px] resize-none"
10341
10429
  }
10342
- ), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex justify-end gap-2" }, /* @__PURE__ */ import_react20.default.createElement(
10430
+ ), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react20.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Links"), /* @__PURE__ */ import_react20.default.createElement("button", { type: "button", onClick: addLinkToNote, className: "text-indigo-400 hover:text-indigo-300 text-[10px] flex items-center gap-1 font-medium" }, /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiPlus, { size: 10 }), " Adicionar Link")), noteLinks.length > 0 && /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-2" }, noteLinks.map((link) => /* @__PURE__ */ import_react20.default.createElement("div", { key: link.id, className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-1" }, /* @__PURE__ */ import_react20.default.createElement(
10431
+ "input",
10432
+ {
10433
+ type: "text",
10434
+ placeholder: "T\xEDtulo",
10435
+ value: link.name,
10436
+ onChange: (e) => updateLinkInNote(link.id, "name", e.target.value),
10437
+ className: "w-1/3 bg-slate-950/50 border border-white/5 rounded px-2 py-1 text-[10px] focus:outline-none focus:border-indigo-500/50"
10438
+ }
10439
+ ), /* @__PURE__ */ import_react20.default.createElement(
10440
+ "input",
10441
+ {
10442
+ type: "text",
10443
+ placeholder: "URL (https://...)",
10444
+ value: link.value,
10445
+ onChange: (e) => updateLinkInNote(link.id, "value", e.target.value),
10446
+ className: "flex-1 bg-slate-950/50 border border-white/5 rounded px-2 py-1 text-[10px] focus:outline-none focus:border-indigo-500/50"
10447
+ }
10448
+ ), /* @__PURE__ */ import_react20.default.createElement("button", { type: "button", onClick: () => removeLinkFromNote(link.id), className: "text-slate-600 hover:text-red-400 transition-colors" }, /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiX, { size: 12 })))))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react20.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Imagens (URLs)"), /* @__PURE__ */ import_react20.default.createElement("button", { type: "button", onClick: addImageToNote, className: "text-indigo-400 hover:text-indigo-300 text-[10px] flex items-center gap-1 font-medium" }, /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiPlus, { size: 10 }), " Adicionar Imagem")), noteImages.length > 0 && /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-2" }, noteImages.map((img) => /* @__PURE__ */ import_react20.default.createElement("div", { key: img.id, className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-1" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex-1 flex items-center gap-2 bg-slate-950/50 border border-white/5 rounded px-2 py-1" }, /* @__PURE__ */ import_react20.default.createElement(FiImage, { size: 10, className: "text-slate-600" }), /* @__PURE__ */ import_react20.default.createElement(
10449
+ "input",
10450
+ {
10451
+ type: "text",
10452
+ placeholder: "URL da Imagem (https://...)",
10453
+ value: img.value,
10454
+ onChange: (e) => updateImageInNote(img.id, e.target.value),
10455
+ className: "flex-1 bg-transparent text-[10px] focus:outline-none"
10456
+ }
10457
+ )), /* @__PURE__ */ import_react20.default.createElement("button", { type: "button", onClick: () => removeImageFromNote(img.id), className: "text-slate-600 hover:text-red-400 transition-colors" }, /* @__PURE__ */ import_react20.default.createElement(import_fi18.FiX, { size: 12 })))))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex justify-end gap-2 pt-2" }, /* @__PURE__ */ import_react20.default.createElement(
10343
10458
  "button",
10344
10459
  {
10345
10460
  type: "button",
10346
10461
  onClick: handleAddTimelineNote,
10347
- disabled: !noteText.trim() || isSaving,
10462
+ disabled: !noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving,
10348
10463
  className: "px-3 py-1.5 rounded-lg bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-semibold transition-colors disabled:opacity-50"
10349
10464
  },
10350
- "Adicionar ao Hist\xF3rico"
10465
+ editingEntryId ? "Salvar nesta Etapa" : "Adicionar ao Hist\xF3rico"
10351
10466
  ))), /* @__PURE__ */ import_react20.default.createElement(
10352
10467
  QuestTimeline,
10353
10468
  {
10354
10469
  timeline,
10355
10470
  viewMembers,
10356
- onOpenImageViewer
10471
+ onOpenImageViewer,
10472
+ canEdit,
10473
+ onAddNote: handleOpenNoteForEntry
10357
10474
  }
10358
10475
  )), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
10359
10476
  const isSelected = size === s;
package/dist/index.mjs CHANGED
@@ -4002,7 +4002,7 @@ import { FiPlus, FiEdit2 as FiEdit22, FiBookOpen } from "react-icons/fi";
4002
4002
 
4003
4003
  // src/components/DescriptionEditModal.jsx
4004
4004
  import React5, { useState as useState6, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
4005
- import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage, FiCheckSquare } from "react-icons/fi";
4005
+ import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage as FiImage2, FiCheckSquare } from "react-icons/fi";
4006
4006
 
4007
4007
  // src/components/SectionImportModal.jsx
4008
4008
  import React4, { useState as useState5, useMemo as useMemo3, useRef as useRef4, useEffect as useEffect4 } from "react";
@@ -4749,7 +4749,7 @@ ${space}${bullet} `);
4749
4749
  className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
4750
4750
  title: "Inserir Imagem (Propriedade ou URL)"
4751
4751
  },
4752
- /* @__PURE__ */ React5.createElement(FiImage, { size: 12 }),
4752
+ /* @__PURE__ */ React5.createElement(FiImage2, { size: 12 }),
4753
4753
  " Imagem"
4754
4754
  ), /* @__PURE__ */ React5.createElement(
4755
4755
  "button",
@@ -4888,7 +4888,7 @@ ${space}${bullet} `);
4888
4888
 
4889
4889
  // src/components/DescriptionDisplay.jsx
4890
4890
  import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
4891
- import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2, FiSave } from "react-icons/fi";
4891
+ import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage3, FiSave } from "react-icons/fi";
4892
4892
  var CodeBlock2 = ({ content, isActive, onClick }) => {
4893
4893
  const [isExpanded, setIsExpanded] = useState7(false);
4894
4894
  const [copied, setCopied] = useState7(false);
@@ -4985,7 +4985,7 @@ var renderTextWithImages = (text, onImageClick) => {
4985
4985
  },
4986
4986
  className: "inline-flex items-center gap-1 text-emerald-400 hover:text-emerald-300 hover:underline decoration-emerald-500/50 underline-offset-2 transition-colors cursor-pointer align-baseline mx-0.5"
4987
4987
  },
4988
- /* @__PURE__ */ React6.createElement(FiImage2, { size: 11 }),
4988
+ /* @__PURE__ */ React6.createElement(FiImage3, { size: 11 }),
4989
4989
  /* @__PURE__ */ React6.createElement("span", null, name)
4990
4990
  );
4991
4991
  }
@@ -9209,7 +9209,7 @@ function InSceneQuestForm({
9209
9209
 
9210
9210
  // src/components/NodeDetailsPanel.jsx
9211
9211
  import React17, { useState as useState18, useEffect as useEffect15, useRef as useRef13 } from "react";
9212
- import { FiPlus as FiPlus7, FiMaximize2 as FiMaximize23, FiX as FiX6, FiCheck as FiCheck10, FiImage as FiImage3, FiEdit2 as FiEdit27, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
9212
+ import { FiPlus as FiPlus7, FiMaximize2 as FiMaximize23, FiX as FiX6, FiCheck as FiCheck10, FiImage as FiImage4, FiEdit2 as FiEdit27, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
9213
9213
  function NodeDetailsPanel({
9214
9214
  node,
9215
9215
  onClose,
@@ -9753,12 +9753,16 @@ var EVENT_ICONS = {
9753
9753
  function QuestTimeline({
9754
9754
  timeline = [],
9755
9755
  viewMembers = [],
9756
- onOpenImageViewer
9756
+ onOpenImageViewer,
9757
+ onAddNote,
9758
+ // Nova prop para adicionar nota a uma etapa específica
9759
+ canEdit = true
9757
9760
  }) {
9758
9761
  const sortedTimeline = [...timeline].sort((a, b) => b.timestamp - a.timestamp);
9759
9762
  const getMemberName = (userId) => {
9760
- const member = viewMembers.find((m) => m.id === userId);
9761
- return (member == null ? void 0 : member.name) || (member == null ? void 0 : member.email) || "Sistema";
9763
+ if (!userId) return "Sistema";
9764
+ const member = viewMembers.find((m) => String(m.id) === String(userId));
9765
+ return (member == null ? void 0 : member.name) || (member == null ? void 0 : member.email) || userId;
9762
9766
  };
9763
9767
  const formatDate = (timestamp) => {
9764
9768
  const date = new Date(timestamp);
@@ -9772,11 +9776,23 @@ function QuestTimeline({
9772
9776
  if (timeline.length === 0) {
9773
9777
  return /* @__PURE__ */ React18.createElement("div", { className: "py-6 flex flex-col items-center justify-center gap-2 border border-white/5 bg-white/5 rounded-xl" }, /* @__PURE__ */ React18.createElement(FiAlertCircle, { className: "text-slate-600", size: 16 }), /* @__PURE__ */ React18.createElement("p", { className: "text-[10px] text-slate-500 font-light uppercase tracking-widest" }, "Nenhum hist\xF3rico dispon\xEDvel"));
9774
9778
  }
9775
- return /* @__PURE__ */ React18.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React18.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider flex items-center gap-2" }, "Hist\xF3rico (Timeline)"), /* @__PURE__ */ React18.createElement("div", { className: "relative pl-6 space-y-6 before:content-[''] before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-[2px] before:bg-white/5" }, sortedTimeline.map((event, index) => {
9779
+ return /* @__PURE__ */ React18.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React18.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider flex items-center gap-2" }, "Hist\xF3rico (Timeline)"), /* @__PURE__ */ React18.createElement("div", { className: "relative pl-10 space-y-6 before:content-[''] before:absolute before:left-[21px] before:top-2 before:bottom-2 before:w-[2px] before:bg-white/5" }, sortedTimeline.map((event, index) => {
9776
9780
  const config = EVENT_ICONS[event.type] || EVENT_ICONS.default;
9777
9781
  const Icon = config.icon;
9778
9782
  const actorName = getMemberName(event.actorId);
9779
- return /* @__PURE__ */ React18.createElement("div", { key: index, className: "relative animate-in fade-in slide-in-from-left-2 duration-300", style: { animationDelay: `${index * 50}ms` } }, /* @__PURE__ */ React18.createElement("div", { className: `absolute -left-[27px] top-0 w-8 h-8 rounded-full ${config.bg} flex items-center justify-center ring-4 ring-slate-950 border border-white/5` }, /* @__PURE__ */ React18.createElement(Icon, { className: config.iconColor || config.color, size: 14 })), /* @__PURE__ */ React18.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center justify-between gap-4" }, /* @__PURE__ */ React18.createElement("span", { className: "text-xs font-semibold text-slate-200" }, actorName), /* @__PURE__ */ React18.createElement("span", { className: "text-[10px] text-slate-500 tabular-nums" }, formatDate(event.timestamp))), /* @__PURE__ */ React18.createElement("p", { className: "text-sm text-slate-400 leading-relaxed" }, event.description), (event.from_status || event.to_status) && /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-1.5 py-1 px-2 rounded-md bg-white/5 border border-white/5 w-fit mt-2" }, /* @__PURE__ */ React18.createElement("span", { className: "text-[10px] text-slate-500" }, event.from_status || "?"), /* @__PURE__ */ React18.createElement(FiArrowRight, { size: 10, className: "text-slate-600" }), /* @__PURE__ */ React18.createElement("span", { className: "text-[10px] text-indigo-300 font-bold" }, event.to_status || "?")), event.metadata && Object.keys(event.metadata).length > 0 && /* @__PURE__ */ React18.createElement("div", { className: "mt-2 text-[10px] grid grid-cols-2 gap-2 p-2 bg-slate-900/50 rounded border border-white/5" }, Object.entries(event.metadata).map(([key, value]) => /* @__PURE__ */ React18.createElement("div", { key, className: "flex flex-col gap-0.5" }, /* @__PURE__ */ React18.createElement("span", { className: "text-slate-500 capitalize" }, key.replace(/_/g, " ")), /* @__PURE__ */ React18.createElement("span", { className: "text-slate-300 truncate font-mono" }, typeof value === "string" ? value : JSON.stringify(value))))), event.links && event.links.length > 0 && /* @__PURE__ */ React18.createElement("div", { className: "flex flex-wrap gap-2 mt-2" }, event.links.map((link, lIdx) => /* @__PURE__ */ React18.createElement(
9783
+ return /* @__PURE__ */ React18.createElement("div", { key: event.id || index, className: "relative animate-in fade-in slide-in-from-left-2 duration-300", style: { animationDelay: `${index * 50}ms` } }, /* @__PURE__ */ React18.createElement("div", { className: `absolute -left-[35px] top-0 w-8 h-8 rounded-full ${config.bg} flex items-center justify-center ring-4 ring-slate-950 border border-white/5` }, /* @__PURE__ */ React18.createElement(Icon, { className: config.iconColor || config.color, size: 14 })), /* @__PURE__ */ React18.createElement("div", { className: "group space-y-1" }, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center justify-between gap-4" }, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React18.createElement("span", { className: "text-xs font-semibold text-slate-200" }, actorName), canEdit && onAddNote && /* @__PURE__ */ React18.createElement(
9784
+ "button",
9785
+ {
9786
+ onClick: () => onAddNote(event),
9787
+ className: "opacity-0 group-hover:opacity-100 p-1 rounded-md hover:bg-white/5 text-slate-500 hover:text-indigo-400 transition-all",
9788
+ title: "Adicionar detalhe/anexo a esta etapa"
9789
+ },
9790
+ /* @__PURE__ */ React18.createElement(FiPlusCircle, { size: 12 })
9791
+ )), /* @__PURE__ */ React18.createElement("span", { className: "text-[10px] text-slate-500 tabular-nums" }, formatDate(event.timestamp))), /* @__PURE__ */ React18.createElement("p", { className: "text-sm text-slate-400 leading-relaxed" }, event.description), event.notes && /* @__PURE__ */ React18.createElement("div", { className: "mt-1 py-1 px-2 rounded bg-indigo-500/5 border-l-2 border-indigo-500/30" }, /* @__PURE__ */ React18.createElement("p", { className: "text-[11px] text-slate-300 italic whitespace-pre-wrap" }, event.notes)), (event.from_status || event.to_status) && /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-1.5 py-1 px-2 rounded-md bg-white/5 border border-white/5 w-fit mt-2" }, /* @__PURE__ */ React18.createElement("span", { className: "text-[10px] text-slate-500" }, event.from_status || "?"), /* @__PURE__ */ React18.createElement(FiArrowRight, { size: 10, className: "text-slate-600" }), /* @__PURE__ */ React18.createElement("span", { className: "text-[10px] text-indigo-300 font-bold" }, event.to_status || "?")), event.metadata && Object.keys(event.metadata).length > 0 && /* @__PURE__ */ React18.createElement("div", { className: "mt-2 text-[10px] grid grid-cols-2 gap-2 p-2 bg-slate-900/50 rounded border border-white/5" }, Object.entries(event.metadata).map(([key, value]) => {
9792
+ const isAssigneeId = key.toLowerCase().includes("assignee_id") || key.toLowerCase().includes("respons\xE1vel") || key.toLowerCase().includes("assignee id");
9793
+ const displayValue = isAssigneeId && typeof value === "string" ? getMemberName(value) : typeof value === "string" ? value : JSON.stringify(value);
9794
+ return /* @__PURE__ */ React18.createElement("div", { key, className: "flex flex-col gap-0.5" }, /* @__PURE__ */ React18.createElement("span", { className: "text-slate-500 capitalize" }, key.replace(/_/g, " ")), /* @__PURE__ */ React18.createElement("span", { className: `${isAssigneeId ? "text-indigo-300 font-medium" : "text-slate-300"} truncate font-mono` }, displayValue));
9795
+ })), event.links && event.links.length > 0 && /* @__PURE__ */ React18.createElement("div", { className: "flex flex-wrap gap-2 mt-2" }, event.links.map((link, lIdx) => /* @__PURE__ */ React18.createElement(
9780
9796
  "a",
9781
9797
  {
9782
9798
  key: lIdx,
@@ -9793,10 +9809,10 @@ function QuestTimeline({
9793
9809
  key: iIdx,
9794
9810
  type: "button",
9795
9811
  onClick: () => onOpenImageViewer == null ? void 0 : onOpenImageViewer(event.images, iIdx),
9796
- className: "relative w-12 h-12 rounded border border-white/10 overflow-hidden hover:border-sky-500/50 transition-colors group"
9812
+ className: "relative w-12 h-12 rounded border border-white/10 overflow-hidden hover:border-sky-500/50 transition-colors group/img"
9797
9813
  },
9798
9814
  /* @__PURE__ */ React18.createElement("img", { src: img.value, alt: img.name, className: "w-full h-full object-cover" }),
9799
- /* @__PURE__ */ React18.createElement("div", { className: "absolute inset-0 bg-slate-900/40 opacity-0 group-hover:opacity-100 flex items-center justify-center transition-opacity" }, /* @__PURE__ */ React18.createElement(FiSearch6, { size: 12, className: "text-white" }))
9815
+ /* @__PURE__ */ React18.createElement("div", { className: "absolute inset-0 bg-slate-900/40 opacity-0 group-hover/img:opacity-100 flex items-center justify-center transition-opacity" }, /* @__PURE__ */ React18.createElement(FiSearch6, { size: 12, className: "text-white" }))
9800
9816
  )))));
9801
9817
  })));
9802
9818
  }
@@ -9859,7 +9875,11 @@ function QuestDetailsPanel({
9859
9875
  const [isLinkCopied, setIsLinkCopied] = useState19(false);
9860
9876
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState19(false);
9861
9877
  const [noteText, setNoteText] = useState19("");
9878
+ const [noteLinks, setNoteLinks] = useState19([]);
9879
+ const [noteImages, setNoteImages] = useState19([]);
9862
9880
  const [isNoteFormOpen, setIsNoteFormOpen] = useState19(false);
9881
+ const [editingEntryId, setEditingEntryId] = useState19(null);
9882
+ const [editingEntryLabel, setEditingEntryLabel] = useState19("");
9863
9883
  const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
9864
9884
  const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
9865
9885
  initialWidth: isReadMode ? 700 : 440,
@@ -9991,11 +10011,30 @@ function QuestDetailsPanel({
9991
10011
  }
9992
10012
  };
9993
10013
  const handleAddTimelineNote = async () => {
9994
- if (!noteText.trim() || isSaving) return;
10014
+ if (!noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving) return;
9995
10015
  setIsSaving(true);
9996
10016
  const actorId = (currentUser == null ? void 0 : currentUser.id) || "unknown";
9997
- const newEntry = createTimelineEntry(actorId, noteText, "comment");
9998
- const updatedTimeline = [...timeline, newEntry];
10017
+ let updatedTimeline;
10018
+ if (editingEntryId) {
10019
+ updatedTimeline = timeline.map((entry) => {
10020
+ if (entry.id === editingEntryId) {
10021
+ return {
10022
+ ...entry,
10023
+ notes: noteText.trim() ? entry.notes ? `${entry.notes}
10024
+ ${noteText}` : noteText : entry.notes,
10025
+ links: [...entry.links || [], ...noteLinks],
10026
+ images: [...entry.images || [], ...noteImages]
10027
+ };
10028
+ }
10029
+ return entry;
10030
+ });
10031
+ } else {
10032
+ const newEntry = createTimelineEntry(actorId, noteText, "comment", {
10033
+ links: noteLinks,
10034
+ images: noteImages
10035
+ });
10036
+ updatedTimeline = [...timeline, newEntry];
10037
+ }
9999
10038
  try {
10000
10039
  const nodeToSave = {
10001
10040
  ...node,
@@ -10005,13 +10044,47 @@ function QuestDetailsPanel({
10005
10044
  setTimeline(updatedTimeline);
10006
10045
  onDataUpdate(nodeToSave);
10007
10046
  setNoteText("");
10047
+ setNoteLinks([]);
10048
+ setNoteImages([]);
10008
10049
  setIsNoteFormOpen(false);
10050
+ setEditingEntryId(null);
10051
+ setEditingEntryLabel("");
10009
10052
  } catch (error) {
10010
10053
  console.error("Erro ao adicionar nota:", error);
10011
10054
  } finally {
10012
10055
  setIsSaving(false);
10013
10056
  }
10014
10057
  };
10058
+ const handleOpenNoteForEntry = (entry) => {
10059
+ setEditingEntryId(entry.id);
10060
+ setEditingEntryLabel(entry.description);
10061
+ setNoteText("");
10062
+ setNoteLinks([]);
10063
+ setNoteImages([]);
10064
+ setIsNoteFormOpen(true);
10065
+ setTimeout(() => {
10066
+ const form = document.getElementById("quest-note-form");
10067
+ form == null ? void 0 : form.scrollIntoView({ behavior: "smooth", block: "center" });
10068
+ }, 100);
10069
+ };
10070
+ const addLinkToNote = () => {
10071
+ setNoteLinks([...noteLinks, { id: v4_default(), name: "", value: "" }]);
10072
+ };
10073
+ const removeLinkFromNote = (id) => {
10074
+ setNoteLinks(noteLinks.filter((l) => l.id !== id));
10075
+ };
10076
+ const updateLinkInNote = (id, field, val) => {
10077
+ setNoteLinks(noteLinks.map((l) => l.id === id ? { ...l, [field]: val } : l));
10078
+ };
10079
+ const addImageToNote = () => {
10080
+ setNoteImages([...noteImages, { id: v4_default(), name: "Image", value: "" }]);
10081
+ };
10082
+ const removeImageFromNote = (id) => {
10083
+ setNoteImages(noteImages.filter((img) => img.id !== id));
10084
+ };
10085
+ const updateImageInNote = (id, val) => {
10086
+ setNoteImages(noteImages.map((img) => img.id === id ? { ...img, value: val } : img));
10087
+ };
10015
10088
  const handleStatusChange = (newStatus) => {
10016
10089
  setStatus(newStatus);
10017
10090
  const newColor = QUEST_STATUS_COLORS3[newStatus];
@@ -10355,34 +10428,78 @@ function QuestDetailsPanel({
10355
10428
  "button",
10356
10429
  {
10357
10430
  type: "button",
10358
- onClick: () => setIsNoteFormOpen(!isNoteFormOpen),
10431
+ onClick: () => {
10432
+ if (isNoteFormOpen && editingEntryId) {
10433
+ setEditingEntryId(null);
10434
+ setEditingEntryLabel("");
10435
+ setNoteText("");
10436
+ setNoteLinks([]);
10437
+ setNoteImages([]);
10438
+ } else {
10439
+ setIsNoteFormOpen(!isNoteFormOpen);
10440
+ setEditingEntryId(null);
10441
+ setEditingEntryLabel("");
10442
+ }
10443
+ },
10359
10444
  className: "flex items-center gap-1.5 px-2 py-1 text-[10px] rounded-md bg-white/5 hover:bg-white/10 border border-white/10 transition-colors text-slate-300"
10360
10445
  },
10361
- isNoteFormOpen ? /* @__PURE__ */ React19.createElement(FiX7, { size: 12 }) : /* @__PURE__ */ React19.createElement(FiPlus8, { size: 12 }),
10362
- isNoteFormOpen ? "Cancelar" : "Nova Nota"
10363
- )), isNoteFormOpen && /* @__PURE__ */ React19.createElement("div", { className: "mb-6 p-4 rounded-xl bg-white/5 border border-white/5 space-y-3 animate-in fade-in slide-in-from-top-2" }, /* @__PURE__ */ React19.createElement(
10446
+ isNoteFormOpen && !editingEntryId ? /* @__PURE__ */ React19.createElement(FiX7, { size: 12 }) : /* @__PURE__ */ React19.createElement(FiPlus8, { size: 12 }),
10447
+ isNoteFormOpen && !editingEntryId ? "Cancelar" : "Nova Nota"
10448
+ )), isNoteFormOpen && /* @__PURE__ */ React19.createElement("div", { id: "quest-note-form", className: "mb-6 p-4 rounded-xl bg-white/5 border border-white/5 space-y-3 animate-in fade-in slide-in-from-top-2 border-l-4 border-l-indigo-500/40" }, editingEntryId && /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between mb-2 pb-2 border-b border-white/5" }, /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React19.createElement("span", { className: "text-[10px] text-indigo-400 font-bold uppercase tracking-wider" }, "Adicionando \xE0 etapa:"), /* @__PURE__ */ React19.createElement("span", { className: "text-xs text-slate-300 italic truncate max-w-[250px]" }, editingEntryLabel)), /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: () => {
10449
+ setIsNoteFormOpen(false);
10450
+ setEditingEntryId(null);
10451
+ }, className: "text-slate-500 hover:text-white" }, /* @__PURE__ */ React19.createElement(FiX7, { size: 14 }))), /* @__PURE__ */ React19.createElement(
10364
10452
  "textarea",
10365
10453
  {
10366
10454
  value: noteText,
10367
10455
  onChange: (e) => setNoteText(e.target.value),
10368
- placeholder: "Escreva uma observa\xE7\xE3o no hist\xF3rico...",
10456
+ placeholder: editingEntryId ? "Adicione uma observa\xE7\xE3o a esta etapa..." : "Escreva uma observa\xE7\xE3o no hist\xF3rico...",
10369
10457
  className: "w-full bg-slate-900/50 p-3 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-500/50 min-h-[80px] resize-none"
10370
10458
  }
10371
- ), /* @__PURE__ */ React19.createElement("div", { className: "flex justify-end gap-2" }, /* @__PURE__ */ React19.createElement(
10459
+ ), /* @__PURE__ */ React19.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React19.createElement("span", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Links"), /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: addLinkToNote, className: "text-indigo-400 hover:text-indigo-300 text-[10px] flex items-center gap-1 font-medium" }, /* @__PURE__ */ React19.createElement(FiPlus8, { size: 10 }), " Adicionar Link")), noteLinks.length > 0 && /* @__PURE__ */ React19.createElement("div", { className: "space-y-2" }, noteLinks.map((link) => /* @__PURE__ */ React19.createElement("div", { key: link.id, className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-1" }, /* @__PURE__ */ React19.createElement(
10460
+ "input",
10461
+ {
10462
+ type: "text",
10463
+ placeholder: "T\xEDtulo",
10464
+ value: link.name,
10465
+ onChange: (e) => updateLinkInNote(link.id, "name", e.target.value),
10466
+ className: "w-1/3 bg-slate-950/50 border border-white/5 rounded px-2 py-1 text-[10px] focus:outline-none focus:border-indigo-500/50"
10467
+ }
10468
+ ), /* @__PURE__ */ React19.createElement(
10469
+ "input",
10470
+ {
10471
+ type: "text",
10472
+ placeholder: "URL (https://...)",
10473
+ value: link.value,
10474
+ onChange: (e) => updateLinkInNote(link.id, "value", e.target.value),
10475
+ className: "flex-1 bg-slate-950/50 border border-white/5 rounded px-2 py-1 text-[10px] focus:outline-none focus:border-indigo-500/50"
10476
+ }
10477
+ ), /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: () => removeLinkFromNote(link.id), className: "text-slate-600 hover:text-red-400 transition-colors" }, /* @__PURE__ */ React19.createElement(FiX7, { size: 12 })))))), /* @__PURE__ */ React19.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React19.createElement("span", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Imagens (URLs)"), /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: addImageToNote, className: "text-indigo-400 hover:text-indigo-300 text-[10px] flex items-center gap-1 font-medium" }, /* @__PURE__ */ React19.createElement(FiPlus8, { size: 10 }), " Adicionar Imagem")), noteImages.length > 0 && /* @__PURE__ */ React19.createElement("div", { className: "space-y-2" }, noteImages.map((img) => /* @__PURE__ */ React19.createElement("div", { key: img.id, className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-1" }, /* @__PURE__ */ React19.createElement("div", { className: "flex-1 flex items-center gap-2 bg-slate-950/50 border border-white/5 rounded px-2 py-1" }, /* @__PURE__ */ React19.createElement(FiImage, { size: 10, className: "text-slate-600" }), /* @__PURE__ */ React19.createElement(
10478
+ "input",
10479
+ {
10480
+ type: "text",
10481
+ placeholder: "URL da Imagem (https://...)",
10482
+ value: img.value,
10483
+ onChange: (e) => updateImageInNote(img.id, e.target.value),
10484
+ className: "flex-1 bg-transparent text-[10px] focus:outline-none"
10485
+ }
10486
+ )), /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: () => removeImageFromNote(img.id), className: "text-slate-600 hover:text-red-400 transition-colors" }, /* @__PURE__ */ React19.createElement(FiX7, { size: 12 })))))), /* @__PURE__ */ React19.createElement("div", { className: "flex justify-end gap-2 pt-2" }, /* @__PURE__ */ React19.createElement(
10372
10487
  "button",
10373
10488
  {
10374
10489
  type: "button",
10375
10490
  onClick: handleAddTimelineNote,
10376
- disabled: !noteText.trim() || isSaving,
10491
+ disabled: !noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving,
10377
10492
  className: "px-3 py-1.5 rounded-lg bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-semibold transition-colors disabled:opacity-50"
10378
10493
  },
10379
- "Adicionar ao Hist\xF3rico"
10494
+ editingEntryId ? "Salvar nesta Etapa" : "Adicionar ao Hist\xF3rico"
10380
10495
  ))), /* @__PURE__ */ React19.createElement(
10381
10496
  QuestTimeline,
10382
10497
  {
10383
10498
  timeline,
10384
10499
  viewMembers,
10385
- onOpenImageViewer
10500
+ onOpenImageViewer,
10501
+ canEdit,
10502
+ onAddNote: handleOpenNoteForEntry
10386
10503
  }
10387
10504
  )), /* @__PURE__ */ React19.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
10388
10505
  const isSelected = size === s;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.5-dev.31",
3
+ "version": "1.2.5-dev.33",
4
4
  "description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
5
5
  "author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
6
6
  "license": "UNLICENSED",