@lv-x-software-house/x_view 1.2.5-dev.43 → 1.2.5-dev.44

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 +159 -70
  2. package/dist/index.mjs +159 -70
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1334,6 +1334,15 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
1334
1334
  label.name = "label";
1335
1335
  mesh.userData.labelObject = label;
1336
1336
  mesh.userData.labelOffset = new THREE.Vector3(0, 3.8, 0);
1337
+ if (nodeData.is_quest && nodeData.Date) {
1338
+ const timeInfo = parseDateProp(nodeData.Date);
1339
+ if (!timeInfo.isUndated && timeInfo.label) {
1340
+ const dateSprite = createTextSprite(timeInfo.label, 36);
1341
+ dateSprite.name = "questDateLabel";
1342
+ dateSprite.position.set(0, -5.5, 0);
1343
+ mesh.add(dateSprite);
1344
+ }
1345
+ }
1337
1346
  return mesh;
1338
1347
  };
1339
1348
  var updateExistingNodeVisuals = (state, updatedNode) => {
@@ -3321,9 +3330,14 @@ var userActionHandlers = {
3321
3330
  };
3322
3331
  specificParentData.nodes.push(nextQuestNode);
3323
3332
  if (stateRef.current.nodeObjects[String(nodeToSave.id)]) {
3324
- const pos = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
3325
- pos.x += 12;
3326
- addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
3333
+ const oldMeshPosition = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
3334
+ setTimeout(() => {
3335
+ if (stateRef.current && stateRef.current.graphGroup) {
3336
+ const pos = oldMeshPosition.clone();
3337
+ pos.x += 12;
3338
+ addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
3339
+ }
3340
+ }, 2e3);
3327
3341
  }
3328
3342
  }
3329
3343
  }
@@ -4266,6 +4280,78 @@ function calculateNextRecurrenceDate(config) {
4266
4280
  confirmed: true
4267
4281
  };
4268
4282
  }
4283
+ var parseDate = (str) => {
4284
+ if (!str) return null;
4285
+ const parts = str.split("/");
4286
+ if (parts.length === 3) {
4287
+ const day = parseInt(parts[0], 10);
4288
+ const month = parseInt(parts[1], 10) - 1;
4289
+ const year = parseInt(parts[2], 10);
4290
+ if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
4291
+ return new Date(year, month, day);
4292
+ }
4293
+ }
4294
+ return null;
4295
+ };
4296
+ var parseDateProp = (dateProp) => {
4297
+ let info = { isUndated: true, label: "", type: "point" };
4298
+ if (!dateProp) return info;
4299
+ if (dateProp.type === "Data") {
4300
+ const d = parseDate(dateProp.value);
4301
+ if (d) {
4302
+ info = { startDate: d, endDate: d, label: dateProp.value, type: "point", isUndated: false };
4303
+ }
4304
+ } else if (dateProp.type === "Date Interval" || dateProp.type === "Date Range" || dateProp.type === "interval") {
4305
+ const sd = parseDate(dateProp.start || dateProp.value);
4306
+ const ed = parseDate(dateProp.end);
4307
+ if (sd) {
4308
+ info = {
4309
+ startDate: sd,
4310
+ endDate: ed || sd,
4311
+ label: `${dateProp.start || dateProp.value}${ed ? " - " + dateProp.end : ""}`,
4312
+ type: ed ? "interval" : "point",
4313
+ isUndated: false
4314
+ };
4315
+ }
4316
+ } else if (dateProp.date) {
4317
+ const d = parseDate(dateProp.date);
4318
+ if (d)
4319
+ info = {
4320
+ startDate: d,
4321
+ endDate: d,
4322
+ label: dateProp.date,
4323
+ type: "point",
4324
+ isUndated: false
4325
+ };
4326
+ } else if (dateProp.year) {
4327
+ const y = parseInt(dateProp.year, 10);
4328
+ if (!isNaN(y)) {
4329
+ const d = new Date(y, 0, 1);
4330
+ info = {
4331
+ startDate: d,
4332
+ endDate: d,
4333
+ label: String(y),
4334
+ type: "point",
4335
+ isUndated: false
4336
+ };
4337
+ }
4338
+ } else if (dateProp.date_interval && dateProp.date_interval.start) {
4339
+ const sY = parseInt(dateProp.date_interval.start, 10);
4340
+ const eY = parseInt(dateProp.date_interval.end, 10) || sY;
4341
+ if (!isNaN(sY)) {
4342
+ const sd = new Date(sY, 0, 1);
4343
+ const ed = new Date(eY, 11, 31);
4344
+ info = {
4345
+ startDate: sd,
4346
+ endDate: ed,
4347
+ label: `${sY} - ${eY}`,
4348
+ type: "interval",
4349
+ isUndated: false
4350
+ };
4351
+ }
4352
+ }
4353
+ return info;
4354
+ };
4269
4355
 
4270
4356
  // src/components/CustomPropertyDisplay.jsx
4271
4357
  var import_react4 = __toESM(require("react"));
@@ -9472,7 +9558,7 @@ function InSceneQuestForm({
9472
9558
  textureImageUrl: null,
9473
9559
  reviewStack,
9474
9560
  timeline: initialTimeline,
9475
- Date: questDate,
9561
+ Date: questDate ? { ...questDate, confirmed: true } : null,
9476
9562
  recurrence_config: recurrenceConfig,
9477
9563
  ...additionalData
9478
9564
  });
@@ -10936,7 +11022,7 @@ ${noteText}` : noteText : entry.notes,
10936
11022
  description_sections: processedSections,
10937
11023
  intensity,
10938
11024
  recurrence_config: currentRecurrenceConfig,
10939
- Date: questDate,
11025
+ Date: questDate ? { ...questDate, confirmed: true } : null,
10940
11026
  useImageAsTexture: false,
10941
11027
  textureImageUrl: null,
10942
11028
  is_quest: true,
@@ -13499,7 +13585,7 @@ function XViewScene({
13499
13585
  }
13500
13586
  }
13501
13587
  Object.values(nodeObjects).forEach((mesh) => {
13502
- const oldLabel = mesh.getObjectByName("timelineLabel") || mesh.getObjectByName("questDateLabel");
13588
+ const oldLabel = mesh.getObjectByName("timelineLabel");
13503
13589
  if (oldLabel) {
13504
13590
  mesh.remove(oldLabel);
13505
13591
  if (oldLabel.material.map) oldLabel.material.map.dispose();
@@ -13510,7 +13596,7 @@ function XViewScene({
13510
13596
  });
13511
13597
  const timelineNodes = [];
13512
13598
  const allTimePoints = /* @__PURE__ */ new Set();
13513
- const parseDate = (str) => {
13599
+ const parseDate2 = (str) => {
13514
13600
  const parts = str.split("/");
13515
13601
  if (parts.length === 3) {
13516
13602
  const day = parseInt(parts[0], 10);
@@ -13527,7 +13613,7 @@ function XViewScene({
13527
13613
  let nodeInfo = { mesh, type: "point", label: "", isUndated: true };
13528
13614
  if (dateProp) {
13529
13615
  if (dateProp.date) {
13530
- const date = parseDate(dateProp.date);
13616
+ const date = parseDate2(dateProp.date);
13531
13617
  if (date) {
13532
13618
  nodeInfo.startDate = date;
13533
13619
  nodeInfo.endDate = date;
@@ -13673,7 +13759,7 @@ function XViewScene({
13673
13759
  });
13674
13760
  const timelineNodes = [];
13675
13761
  const allTimePoints = /* @__PURE__ */ new Set();
13676
- const parseDate = (str) => {
13762
+ const parseDate2 = (str) => {
13677
13763
  const parts = str.split("/");
13678
13764
  if (parts.length === 3) {
13679
13765
  const day = parseInt(parts[0], 10);
@@ -13690,7 +13776,7 @@ function XViewScene({
13690
13776
  if (!dateProp) return;
13691
13777
  let nodeInfo = { mesh, type: "point", label: "" };
13692
13778
  if (dateProp.date) {
13693
- const date = parseDate(dateProp.date);
13779
+ const date = parseDate2(dateProp.date);
13694
13780
  if (date) {
13695
13781
  nodeInfo.startDate = date;
13696
13782
  nodeInfo.endDate = date;
@@ -13932,16 +14018,8 @@ function XViewScene({
13932
14018
  );
13933
14019
  const handleActivateQuestLens = (0, import_react28.useCallback)(({ assigneeId, status: status2 }) => {
13934
14020
  var _a2;
13935
- const { nodeObjects, tweenGroup, graphGroup, timelineIntervalsGroup } = stateRef.current;
14021
+ const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
13936
14022
  if (!nodeObjects || !tweenGroup || !graphGroup) return;
13937
- Object.values(nodeObjects).forEach((mesh) => {
13938
- const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
13939
- if (oldLabel) {
13940
- mesh.remove(oldLabel);
13941
- if (oldLabel.material.map) oldLabel.material.map.dispose();
13942
- oldLabel.material.dispose();
13943
- }
13944
- });
13945
14023
  const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
13946
14024
  const filteredQuests = allQuests.filter((q) => {
13947
14025
  const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
@@ -13963,61 +14041,39 @@ function XViewScene({
13963
14041
  questsByStatus[q.status].push(q);
13964
14042
  }
13965
14043
  });
13966
- const parseDate = (str) => {
13967
- if (!str) return null;
13968
- const parts = str.split("/");
13969
- if (parts.length === 3) {
13970
- const day = parseInt(parts[0], 10);
13971
- const month = parseInt(parts[1], 10) - 1;
13972
- const year = parseInt(parts[2], 10);
13973
- if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
13974
- return new Date(year, month, day);
13975
- }
13976
- }
13977
- return null;
13978
- };
13979
- const timePoints = /* @__PURE__ */ new Set();
13980
14044
  const questTimeInfos = /* @__PURE__ */ new Map();
14045
+ const allActiveTimePoints = /* @__PURE__ */ new Set();
13981
14046
  filteredQuests.forEach((q) => {
13982
- const dateProp = q.Date;
13983
- let info = { isUndated: true, label: "" };
13984
- if (dateProp) {
13985
- if (dateProp.date) {
13986
- const d = parseDate(dateProp.date);
13987
- if (d) {
13988
- info = { startDate: d, endDate: d, label: dateProp.date, isUndated: false };
13989
- timePoints.add(d.getTime());
13990
- }
13991
- } else if (dateProp.year) {
13992
- const y = parseInt(dateProp.year, 10);
13993
- if (!isNaN(y)) {
13994
- const d = new Date(y, 0, 1);
13995
- info = { startDate: d, endDate: d, label: String(y), isUndated: false };
13996
- timePoints.add(d.getTime());
13997
- }
13998
- } else if (dateProp.date_interval && dateProp.date_interval.start) {
13999
- const sY = parseInt(dateProp.date_interval.start, 10);
14000
- const eY = parseInt(dateProp.date_interval.end, 10) || sY;
14001
- if (!isNaN(sY)) {
14002
- const sd = new Date(sY, 0, 1);
14003
- const ed = new Date(eY, 11, 31);
14004
- info = { startDate: sd, endDate: ed, label: `${sY}-${eY}`, isUndated: false };
14005
- timePoints.add(sd.getTime());
14006
- timePoints.add(ed.getTime());
14007
- }
14047
+ const info = parseDateProp(q.Date);
14048
+ questTimeInfos.set(String(q.id), info);
14049
+ if (!info.isUndated) {
14050
+ allActiveTimePoints.add(info.startDate.getTime());
14051
+ if (info.endDate && info.type === "interval") {
14052
+ allActiveTimePoints.add(info.endDate.getTime());
14008
14053
  }
14009
14054
  }
14010
- questTimeInfos.set(String(q.id), info);
14011
14055
  });
14012
- const sortedTimePoints = Array.from(timePoints).sort((a, b) => a - b);
14056
+ const sortedTimePoints = Array.from(allActiveTimePoints).sort((a, b) => a - b);
14013
14057
  const timeToYMap = /* @__PURE__ */ new Map();
14014
- if (sortedTimePoints.length > 0) {
14015
- const maxIdx = sortedTimePoints.length - 1;
14016
- sortedTimePoints.forEach((t, i) => {
14017
- timeToYMap.set(t, (i - maxIdx) * (QUEST_LENS_ROW_SPACING || 30));
14018
- });
14019
- }
14058
+ sortedTimePoints.forEach((ms, idx) => {
14059
+ timeToYMap.set(ms, idx * TIMELINE_LAYER_SPACING_Y);
14060
+ });
14020
14061
  const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
14062
+ Object.values(nodeObjects).forEach((mesh) => {
14063
+ const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
14064
+ if (oldLabel) {
14065
+ mesh.remove(oldLabel);
14066
+ if (oldLabel.material) oldLabel.material.dispose();
14067
+ }
14068
+ if (mesh.userData.timelineIntervalBar) {
14069
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineIntervalBar);
14070
+ mesh.userData.timelineIntervalBar = null;
14071
+ }
14072
+ if (mesh.userData.timelineEndLabel) {
14073
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineEndLabel);
14074
+ mesh.userData.timelineEndLabel = null;
14075
+ }
14076
+ });
14021
14077
  Object.keys(nodeObjects).forEach((id) => {
14022
14078
  const mesh = nodeObjects[id];
14023
14079
  const isFilteredQuest = filteredQuests.some(
@@ -14059,20 +14115,53 @@ function XViewScene({
14059
14115
  targetY = timeToYMap.get(timeInfo.startDate.getTime());
14060
14116
  } else {
14061
14117
  const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
14062
- targetY = -80 - rowIndex * (QUEST_LENS_ROW_SPACING || 30) - undatedOffset;
14118
+ targetY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
14063
14119
  }
14064
14120
  const lensTween = new import_tween2.Tween(mesh.position).to({ x: colX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
14065
14121
  tweenGroup.add(lensTween);
14066
14122
  lensTween.start();
14067
- if (!timeInfo.isUndated && timeInfo.label) {
14123
+ if (!timeInfo.isUndated && timeInfo.label && !mesh.getObjectByName("questDateLabel")) {
14068
14124
  const dateSprite = createTextSprite(timeInfo.label, 36);
14069
14125
  dateSprite.name = "questDateLabel";
14070
14126
  dateSprite.position.set(0, -5.5, 0);
14071
14127
  mesh.add(dateSprite);
14072
14128
  }
14129
+ if (timeInfo.type === "interval" && timeToYMap.has(timeInfo.endDate.getTime())) {
14130
+ const endY = timeToYMap.get(timeInfo.endDate.getTime());
14131
+ if (Math.abs(endY - targetY) > 0.1) {
14132
+ const barHeight = Math.abs(endY - targetY);
14133
+ const barGeometry = new THREE3.CylinderGeometry(
14134
+ TIMELINE_INTERVAL_BAR_RADIUS,
14135
+ TIMELINE_INTERVAL_BAR_RADIUS,
14136
+ 1,
14137
+ 16
14138
+ );
14139
+ const barMaterial = new THREE3.MeshStandardMaterial({
14140
+ color: TIMELINE_GOLD_COLOR,
14141
+ emissive: 12092939,
14142
+ emissiveIntensity: 0.4,
14143
+ transparent: true,
14144
+ opacity: TIMELINE_INTERVAL_BAR_OPACITY,
14145
+ roughness: 0.3,
14146
+ metalness: 0.8
14147
+ });
14148
+ const intervalBar = new THREE3.Mesh(barGeometry, barMaterial);
14149
+ intervalBar.userData.associatedNodeId = mesh.userData.id;
14150
+ const endPosition = new THREE3.Vector3(colX, endY, -0.5);
14151
+ intervalBar.position.set(colX, (targetY + endY) / 2, -0.5);
14152
+ intervalBar.scale.y = barHeight;
14153
+ graphGroup.add(intervalBar);
14154
+ mesh.userData.timelineIntervalBar = intervalBar;
14155
+ const endLabel = createTextSprite(timeInfo.label.split(" - ")[1] || "", 30);
14156
+ endLabel.name = "timelineEndLabel";
14157
+ endLabel.position.set(colX, endY + 4, 0);
14158
+ graphGroup.add(endLabel);
14159
+ mesh.userData.timelineEndLabel = endLabel;
14160
+ }
14161
+ }
14073
14162
  if (mesh.userData.labelObject) {
14074
14163
  const labelTargetPos = new THREE3.Vector3(colX, targetY, 0).add(
14075
- mesh.userData.labelOffset || new THREE3.Vector3(0, -2.5, 0)
14164
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
14076
14165
  );
14077
14166
  const labelTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(import_tween2.Easing.Cubic.InOut);
14078
14167
  tweenGroup.add(labelTween);
package/dist/index.mjs CHANGED
@@ -1295,6 +1295,15 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
1295
1295
  label.name = "label";
1296
1296
  mesh.userData.labelObject = label;
1297
1297
  mesh.userData.labelOffset = new THREE.Vector3(0, 3.8, 0);
1298
+ if (nodeData.is_quest && nodeData.Date) {
1299
+ const timeInfo = parseDateProp(nodeData.Date);
1300
+ if (!timeInfo.isUndated && timeInfo.label) {
1301
+ const dateSprite = createTextSprite(timeInfo.label, 36);
1302
+ dateSprite.name = "questDateLabel";
1303
+ dateSprite.position.set(0, -5.5, 0);
1304
+ mesh.add(dateSprite);
1305
+ }
1306
+ }
1298
1307
  return mesh;
1299
1308
  };
1300
1309
  var updateExistingNodeVisuals = (state, updatedNode) => {
@@ -3282,9 +3291,14 @@ var userActionHandlers = {
3282
3291
  };
3283
3292
  specificParentData.nodes.push(nextQuestNode);
3284
3293
  if (stateRef.current.nodeObjects[String(nodeToSave.id)]) {
3285
- const pos = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
3286
- pos.x += 12;
3287
- addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
3294
+ const oldMeshPosition = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
3295
+ setTimeout(() => {
3296
+ if (stateRef.current && stateRef.current.graphGroup) {
3297
+ const pos = oldMeshPosition.clone();
3298
+ pos.x += 12;
3299
+ addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
3300
+ }
3301
+ }, 2e3);
3288
3302
  }
3289
3303
  }
3290
3304
  }
@@ -4227,6 +4241,78 @@ function calculateNextRecurrenceDate(config) {
4227
4241
  confirmed: true
4228
4242
  };
4229
4243
  }
4244
+ var parseDate = (str) => {
4245
+ if (!str) return null;
4246
+ const parts = str.split("/");
4247
+ if (parts.length === 3) {
4248
+ const day = parseInt(parts[0], 10);
4249
+ const month = parseInt(parts[1], 10) - 1;
4250
+ const year = parseInt(parts[2], 10);
4251
+ if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
4252
+ return new Date(year, month, day);
4253
+ }
4254
+ }
4255
+ return null;
4256
+ };
4257
+ var parseDateProp = (dateProp) => {
4258
+ let info = { isUndated: true, label: "", type: "point" };
4259
+ if (!dateProp) return info;
4260
+ if (dateProp.type === "Data") {
4261
+ const d = parseDate(dateProp.value);
4262
+ if (d) {
4263
+ info = { startDate: d, endDate: d, label: dateProp.value, type: "point", isUndated: false };
4264
+ }
4265
+ } else if (dateProp.type === "Date Interval" || dateProp.type === "Date Range" || dateProp.type === "interval") {
4266
+ const sd = parseDate(dateProp.start || dateProp.value);
4267
+ const ed = parseDate(dateProp.end);
4268
+ if (sd) {
4269
+ info = {
4270
+ startDate: sd,
4271
+ endDate: ed || sd,
4272
+ label: `${dateProp.start || dateProp.value}${ed ? " - " + dateProp.end : ""}`,
4273
+ type: ed ? "interval" : "point",
4274
+ isUndated: false
4275
+ };
4276
+ }
4277
+ } else if (dateProp.date) {
4278
+ const d = parseDate(dateProp.date);
4279
+ if (d)
4280
+ info = {
4281
+ startDate: d,
4282
+ endDate: d,
4283
+ label: dateProp.date,
4284
+ type: "point",
4285
+ isUndated: false
4286
+ };
4287
+ } else if (dateProp.year) {
4288
+ const y = parseInt(dateProp.year, 10);
4289
+ if (!isNaN(y)) {
4290
+ const d = new Date(y, 0, 1);
4291
+ info = {
4292
+ startDate: d,
4293
+ endDate: d,
4294
+ label: String(y),
4295
+ type: "point",
4296
+ isUndated: false
4297
+ };
4298
+ }
4299
+ } else if (dateProp.date_interval && dateProp.date_interval.start) {
4300
+ const sY = parseInt(dateProp.date_interval.start, 10);
4301
+ const eY = parseInt(dateProp.date_interval.end, 10) || sY;
4302
+ if (!isNaN(sY)) {
4303
+ const sd = new Date(sY, 0, 1);
4304
+ const ed = new Date(eY, 11, 31);
4305
+ info = {
4306
+ startDate: sd,
4307
+ endDate: ed,
4308
+ label: `${sY} - ${eY}`,
4309
+ type: "interval",
4310
+ isUndated: false
4311
+ };
4312
+ }
4313
+ }
4314
+ return info;
4315
+ };
4230
4316
 
4231
4317
  // src/components/CustomPropertyDisplay.jsx
4232
4318
  import React3, { useState as useState4, useRef as useRef3, useEffect as useEffect3 } from "react";
@@ -9491,7 +9577,7 @@ function InSceneQuestForm({
9491
9577
  textureImageUrl: null,
9492
9578
  reviewStack,
9493
9579
  timeline: initialTimeline,
9494
- Date: questDate,
9580
+ Date: questDate ? { ...questDate, confirmed: true } : null,
9495
9581
  recurrence_config: recurrenceConfig,
9496
9582
  ...additionalData
9497
9583
  });
@@ -10967,7 +11053,7 @@ ${noteText}` : noteText : entry.notes,
10967
11053
  description_sections: processedSections,
10968
11054
  intensity,
10969
11055
  recurrence_config: currentRecurrenceConfig,
10970
- Date: questDate,
11056
+ Date: questDate ? { ...questDate, confirmed: true } : null,
10971
11057
  useImageAsTexture: false,
10972
11058
  textureImageUrl: null,
10973
11059
  is_quest: true,
@@ -13543,7 +13629,7 @@ function XViewScene({
13543
13629
  }
13544
13630
  }
13545
13631
  Object.values(nodeObjects).forEach((mesh) => {
13546
- const oldLabel = mesh.getObjectByName("timelineLabel") || mesh.getObjectByName("questDateLabel");
13632
+ const oldLabel = mesh.getObjectByName("timelineLabel");
13547
13633
  if (oldLabel) {
13548
13634
  mesh.remove(oldLabel);
13549
13635
  if (oldLabel.material.map) oldLabel.material.map.dispose();
@@ -13554,7 +13640,7 @@ function XViewScene({
13554
13640
  });
13555
13641
  const timelineNodes = [];
13556
13642
  const allTimePoints = /* @__PURE__ */ new Set();
13557
- const parseDate = (str) => {
13643
+ const parseDate2 = (str) => {
13558
13644
  const parts = str.split("/");
13559
13645
  if (parts.length === 3) {
13560
13646
  const day = parseInt(parts[0], 10);
@@ -13571,7 +13657,7 @@ function XViewScene({
13571
13657
  let nodeInfo = { mesh, type: "point", label: "", isUndated: true };
13572
13658
  if (dateProp) {
13573
13659
  if (dateProp.date) {
13574
- const date = parseDate(dateProp.date);
13660
+ const date = parseDate2(dateProp.date);
13575
13661
  if (date) {
13576
13662
  nodeInfo.startDate = date;
13577
13663
  nodeInfo.endDate = date;
@@ -13717,7 +13803,7 @@ function XViewScene({
13717
13803
  });
13718
13804
  const timelineNodes = [];
13719
13805
  const allTimePoints = /* @__PURE__ */ new Set();
13720
- const parseDate = (str) => {
13806
+ const parseDate2 = (str) => {
13721
13807
  const parts = str.split("/");
13722
13808
  if (parts.length === 3) {
13723
13809
  const day = parseInt(parts[0], 10);
@@ -13734,7 +13820,7 @@ function XViewScene({
13734
13820
  if (!dateProp) return;
13735
13821
  let nodeInfo = { mesh, type: "point", label: "" };
13736
13822
  if (dateProp.date) {
13737
- const date = parseDate(dateProp.date);
13823
+ const date = parseDate2(dateProp.date);
13738
13824
  if (date) {
13739
13825
  nodeInfo.startDate = date;
13740
13826
  nodeInfo.endDate = date;
@@ -13976,16 +14062,8 @@ function XViewScene({
13976
14062
  );
13977
14063
  const handleActivateQuestLens = useCallback4(({ assigneeId, status: status2 }) => {
13978
14064
  var _a2;
13979
- const { nodeObjects, tweenGroup, graphGroup, timelineIntervalsGroup } = stateRef.current;
14065
+ const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
13980
14066
  if (!nodeObjects || !tweenGroup || !graphGroup) return;
13981
- Object.values(nodeObjects).forEach((mesh) => {
13982
- const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
13983
- if (oldLabel) {
13984
- mesh.remove(oldLabel);
13985
- if (oldLabel.material.map) oldLabel.material.map.dispose();
13986
- oldLabel.material.dispose();
13987
- }
13988
- });
13989
14067
  const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
13990
14068
  const filteredQuests = allQuests.filter((q) => {
13991
14069
  const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
@@ -14007,61 +14085,39 @@ function XViewScene({
14007
14085
  questsByStatus[q.status].push(q);
14008
14086
  }
14009
14087
  });
14010
- const parseDate = (str) => {
14011
- if (!str) return null;
14012
- const parts = str.split("/");
14013
- if (parts.length === 3) {
14014
- const day = parseInt(parts[0], 10);
14015
- const month = parseInt(parts[1], 10) - 1;
14016
- const year = parseInt(parts[2], 10);
14017
- if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
14018
- return new Date(year, month, day);
14019
- }
14020
- }
14021
- return null;
14022
- };
14023
- const timePoints = /* @__PURE__ */ new Set();
14024
14088
  const questTimeInfos = /* @__PURE__ */ new Map();
14089
+ const allActiveTimePoints = /* @__PURE__ */ new Set();
14025
14090
  filteredQuests.forEach((q) => {
14026
- const dateProp = q.Date;
14027
- let info = { isUndated: true, label: "" };
14028
- if (dateProp) {
14029
- if (dateProp.date) {
14030
- const d = parseDate(dateProp.date);
14031
- if (d) {
14032
- info = { startDate: d, endDate: d, label: dateProp.date, isUndated: false };
14033
- timePoints.add(d.getTime());
14034
- }
14035
- } else if (dateProp.year) {
14036
- const y = parseInt(dateProp.year, 10);
14037
- if (!isNaN(y)) {
14038
- const d = new Date(y, 0, 1);
14039
- info = { startDate: d, endDate: d, label: String(y), isUndated: false };
14040
- timePoints.add(d.getTime());
14041
- }
14042
- } else if (dateProp.date_interval && dateProp.date_interval.start) {
14043
- const sY = parseInt(dateProp.date_interval.start, 10);
14044
- const eY = parseInt(dateProp.date_interval.end, 10) || sY;
14045
- if (!isNaN(sY)) {
14046
- const sd = new Date(sY, 0, 1);
14047
- const ed = new Date(eY, 11, 31);
14048
- info = { startDate: sd, endDate: ed, label: `${sY}-${eY}`, isUndated: false };
14049
- timePoints.add(sd.getTime());
14050
- timePoints.add(ed.getTime());
14051
- }
14091
+ const info = parseDateProp(q.Date);
14092
+ questTimeInfos.set(String(q.id), info);
14093
+ if (!info.isUndated) {
14094
+ allActiveTimePoints.add(info.startDate.getTime());
14095
+ if (info.endDate && info.type === "interval") {
14096
+ allActiveTimePoints.add(info.endDate.getTime());
14052
14097
  }
14053
14098
  }
14054
- questTimeInfos.set(String(q.id), info);
14055
14099
  });
14056
- const sortedTimePoints = Array.from(timePoints).sort((a, b) => a - b);
14100
+ const sortedTimePoints = Array.from(allActiveTimePoints).sort((a, b) => a - b);
14057
14101
  const timeToYMap = /* @__PURE__ */ new Map();
14058
- if (sortedTimePoints.length > 0) {
14059
- const maxIdx = sortedTimePoints.length - 1;
14060
- sortedTimePoints.forEach((t, i) => {
14061
- timeToYMap.set(t, (i - maxIdx) * (QUEST_LENS_ROW_SPACING || 30));
14062
- });
14063
- }
14102
+ sortedTimePoints.forEach((ms, idx) => {
14103
+ timeToYMap.set(ms, idx * TIMELINE_LAYER_SPACING_Y);
14104
+ });
14064
14105
  const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
14106
+ Object.values(nodeObjects).forEach((mesh) => {
14107
+ const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
14108
+ if (oldLabel) {
14109
+ mesh.remove(oldLabel);
14110
+ if (oldLabel.material) oldLabel.material.dispose();
14111
+ }
14112
+ if (mesh.userData.timelineIntervalBar) {
14113
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineIntervalBar);
14114
+ mesh.userData.timelineIntervalBar = null;
14115
+ }
14116
+ if (mesh.userData.timelineEndLabel) {
14117
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineEndLabel);
14118
+ mesh.userData.timelineEndLabel = null;
14119
+ }
14120
+ });
14065
14121
  Object.keys(nodeObjects).forEach((id) => {
14066
14122
  const mesh = nodeObjects[id];
14067
14123
  const isFilteredQuest = filteredQuests.some(
@@ -14103,20 +14159,53 @@ function XViewScene({
14103
14159
  targetY = timeToYMap.get(timeInfo.startDate.getTime());
14104
14160
  } else {
14105
14161
  const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
14106
- targetY = -80 - rowIndex * (QUEST_LENS_ROW_SPACING || 30) - undatedOffset;
14162
+ targetY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
14107
14163
  }
14108
14164
  const lensTween = new Tween2(mesh.position).to({ x: colX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
14109
14165
  tweenGroup.add(lensTween);
14110
14166
  lensTween.start();
14111
- if (!timeInfo.isUndated && timeInfo.label) {
14167
+ if (!timeInfo.isUndated && timeInfo.label && !mesh.getObjectByName("questDateLabel")) {
14112
14168
  const dateSprite = createTextSprite(timeInfo.label, 36);
14113
14169
  dateSprite.name = "questDateLabel";
14114
14170
  dateSprite.position.set(0, -5.5, 0);
14115
14171
  mesh.add(dateSprite);
14116
14172
  }
14173
+ if (timeInfo.type === "interval" && timeToYMap.has(timeInfo.endDate.getTime())) {
14174
+ const endY = timeToYMap.get(timeInfo.endDate.getTime());
14175
+ if (Math.abs(endY - targetY) > 0.1) {
14176
+ const barHeight = Math.abs(endY - targetY);
14177
+ const barGeometry = new THREE3.CylinderGeometry(
14178
+ TIMELINE_INTERVAL_BAR_RADIUS,
14179
+ TIMELINE_INTERVAL_BAR_RADIUS,
14180
+ 1,
14181
+ 16
14182
+ );
14183
+ const barMaterial = new THREE3.MeshStandardMaterial({
14184
+ color: TIMELINE_GOLD_COLOR,
14185
+ emissive: 12092939,
14186
+ emissiveIntensity: 0.4,
14187
+ transparent: true,
14188
+ opacity: TIMELINE_INTERVAL_BAR_OPACITY,
14189
+ roughness: 0.3,
14190
+ metalness: 0.8
14191
+ });
14192
+ const intervalBar = new THREE3.Mesh(barGeometry, barMaterial);
14193
+ intervalBar.userData.associatedNodeId = mesh.userData.id;
14194
+ const endPosition = new THREE3.Vector3(colX, endY, -0.5);
14195
+ intervalBar.position.set(colX, (targetY + endY) / 2, -0.5);
14196
+ intervalBar.scale.y = barHeight;
14197
+ graphGroup.add(intervalBar);
14198
+ mesh.userData.timelineIntervalBar = intervalBar;
14199
+ const endLabel = createTextSprite(timeInfo.label.split(" - ")[1] || "", 30);
14200
+ endLabel.name = "timelineEndLabel";
14201
+ endLabel.position.set(colX, endY + 4, 0);
14202
+ graphGroup.add(endLabel);
14203
+ mesh.userData.timelineEndLabel = endLabel;
14204
+ }
14205
+ }
14117
14206
  if (mesh.userData.labelObject) {
14118
14207
  const labelTargetPos = new THREE3.Vector3(colX, targetY, 0).add(
14119
- mesh.userData.labelOffset || new THREE3.Vector3(0, -2.5, 0)
14208
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
14120
14209
  );
14121
14210
  const labelTween = new Tween2(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(Easing2.Cubic.InOut);
14122
14211
  tweenGroup.add(labelTween);
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.43",
3
+ "version": "1.2.5-dev.44",
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",