@lv-x-software-house/x_view 1.2.5-dev.14 → 1.2.5-dev.15
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 +191 -61
- package/dist/index.mjs +191 -61
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2881,18 +2881,27 @@ function createNewCustomProperty(existingProps = []) {
|
|
|
2881
2881
|
};
|
|
2882
2882
|
}
|
|
2883
2883
|
var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
|
|
2884
|
-
const match = refString.match(
|
|
2884
|
+
const match = refString.match(
|
|
2885
|
+
/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/
|
|
2886
|
+
);
|
|
2885
2887
|
if (!match) return null;
|
|
2886
2888
|
const [_, type, itemId, sectionId] = match;
|
|
2887
2889
|
let sourceItem = null;
|
|
2888
2890
|
if (type === "node") {
|
|
2889
2891
|
sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
|
|
2890
2892
|
} else {
|
|
2891
|
-
sourceItem = availableAncestries.find(
|
|
2893
|
+
sourceItem = availableAncestries.find(
|
|
2894
|
+
(a) => String(a.ancestry_id) === String(itemId)
|
|
2895
|
+
);
|
|
2892
2896
|
}
|
|
2893
2897
|
if (!sourceItem) return null;
|
|
2894
|
-
const sections = parseDescriptionSections(
|
|
2895
|
-
|
|
2898
|
+
const sections = parseDescriptionSections(
|
|
2899
|
+
sourceItem.description,
|
|
2900
|
+
sourceItem.description_sections
|
|
2901
|
+
);
|
|
2902
|
+
const targetSection = sections.find(
|
|
2903
|
+
(s) => String(s.id) === String(sectionId)
|
|
2904
|
+
);
|
|
2896
2905
|
if (!targetSection) return null;
|
|
2897
2906
|
return {
|
|
2898
2907
|
content: targetSection.content,
|
|
@@ -2906,21 +2915,34 @@ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
|
2906
2915
|
let text = rawText;
|
|
2907
2916
|
const allNodes = parentData ? Object.values(parentData).flatMap((f) => f.nodes || []) : [];
|
|
2908
2917
|
const allAncestries = ancestryData || [];
|
|
2909
|
-
text = text.replace(
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2918
|
+
text = text.replace(
|
|
2919
|
+
/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g,
|
|
2920
|
+
(match, type, itemId, sectionId) => {
|
|
2921
|
+
const resolved = resolveDescriptionReference(
|
|
2922
|
+
match,
|
|
2923
|
+
allNodes,
|
|
2924
|
+
allAncestries
|
|
2925
|
+
);
|
|
2926
|
+
if (resolved && !resolved.error) {
|
|
2927
|
+
return resolved.content;
|
|
2928
|
+
}
|
|
2929
|
+
return "[Refer\xEAncia indispon\xEDvel]";
|
|
2913
2930
|
}
|
|
2914
|
-
|
|
2915
|
-
});
|
|
2931
|
+
);
|
|
2916
2932
|
text = text.replace(/\*\/\s*\d+(?::[a-zA-Z0-9-]+)?\s*\//g, "");
|
|
2917
|
-
text = text.replace(
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2933
|
+
text = text.replace(
|
|
2934
|
+
/\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g,
|
|
2935
|
+
(match, nodeId) => {
|
|
2936
|
+
const node = allNodes.find((n) => String(n.id) === String(nodeId));
|
|
2937
|
+
return node ? `@${node.name}` : `@Men\xE7\xE3o`;
|
|
2938
|
+
}
|
|
2939
|
+
);
|
|
2940
|
+
text = text.replace(
|
|
2941
|
+
/\[\[MENTION:image:([^|\]]+)\|?([^\]]*)\]\]/g,
|
|
2942
|
+
(match, url, name) => {
|
|
2943
|
+
return name ? `[Imagem: ${name}]` : `[Imagem]`;
|
|
2944
|
+
}
|
|
2945
|
+
);
|
|
2924
2946
|
text = text.replace(/^#+\s*/gm, "");
|
|
2925
2947
|
text = text.replace(/```[\s\S]*?```/g, "[C\xF3digo]");
|
|
2926
2948
|
text = text.replace(/-\s\[[xX ]\]\s*/g, "\u2022 ");
|
|
@@ -2928,7 +2950,14 @@ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
|
2928
2950
|
return text.trim();
|
|
2929
2951
|
}
|
|
2930
2952
|
function generateTooltipHtml(data, parentData, ancestryData) {
|
|
2931
|
-
const ignoredKeys = [
|
|
2953
|
+
const ignoredKeys = [
|
|
2954
|
+
"id",
|
|
2955
|
+
"name",
|
|
2956
|
+
"type",
|
|
2957
|
+
"color",
|
|
2958
|
+
"_baseEmissiveIntensity",
|
|
2959
|
+
"description"
|
|
2960
|
+
];
|
|
2932
2961
|
const customKeys = Object.keys(data).filter((k) => !ignoredKeys.includes(k));
|
|
2933
2962
|
const extras = customKeys.length;
|
|
2934
2963
|
let typeDisplay = "Node";
|
|
@@ -2943,7 +2972,11 @@ function generateTooltipHtml(data, parentData, ancestryData) {
|
|
|
2943
2972
|
<div style="font-weight:600; font-size: 14px; color: #fff;">${typeDisplay}</div>
|
|
2944
2973
|
<div style="margin-bottom: 2px; color: #e2e8f0;">${data.name || ""}</div>`;
|
|
2945
2974
|
if (data.description) {
|
|
2946
|
-
const cleanDesc = formatDescriptionForTooltip(
|
|
2975
|
+
const cleanDesc = formatDescriptionForTooltip(
|
|
2976
|
+
data.description,
|
|
2977
|
+
parentData,
|
|
2978
|
+
ancestryData
|
|
2979
|
+
);
|
|
2947
2980
|
if (cleanDesc) {
|
|
2948
2981
|
html += `<div style="
|
|
2949
2982
|
margin-top: 6px;
|
|
@@ -2981,7 +3014,11 @@ function generateLinkTooltipHtml(data, parentData, ancestryData) {
|
|
|
2981
3014
|
html += `<div style="font-weight:600; font-size: 14px; color: #a5f3fc; margin-bottom: 4px;">${data.name}</div>`;
|
|
2982
3015
|
}
|
|
2983
3016
|
if (hasDescription) {
|
|
2984
|
-
const cleanDesc = formatDescriptionForTooltip(
|
|
3017
|
+
const cleanDesc = formatDescriptionForTooltip(
|
|
3018
|
+
data.description,
|
|
3019
|
+
parentData,
|
|
3020
|
+
ancestryData
|
|
3021
|
+
);
|
|
2985
3022
|
if (cleanDesc) {
|
|
2986
3023
|
html += `<div style="
|
|
2987
3024
|
display: -webkit-box;
|
|
@@ -3063,7 +3100,8 @@ var IGNORED_KEYS = [
|
|
|
3063
3100
|
"isAddingAbstractionNodes",
|
|
3064
3101
|
"status",
|
|
3065
3102
|
"is_quest",
|
|
3066
|
-
"raw_title"
|
|
3103
|
+
"raw_title",
|
|
3104
|
+
"assignee_id"
|
|
3067
3105
|
];
|
|
3068
3106
|
function extractCustomPropsFromNode(node) {
|
|
3069
3107
|
const customPropTypes = node._customPropTypes || {};
|
|
@@ -3073,16 +3111,40 @@ function extractCustomPropsFromNode(node) {
|
|
|
3073
3111
|
if (t === "date") {
|
|
3074
3112
|
if (val && typeof val === "object") {
|
|
3075
3113
|
if ("date_interval" in val) {
|
|
3076
|
-
return {
|
|
3114
|
+
return {
|
|
3115
|
+
id: v4_default(),
|
|
3116
|
+
key,
|
|
3117
|
+
type: "date",
|
|
3118
|
+
value: {
|
|
3119
|
+
type: "Date Interval",
|
|
3120
|
+
start: val.date_interval.start || "",
|
|
3121
|
+
end: val.date_interval.end || ""
|
|
3122
|
+
}
|
|
3123
|
+
};
|
|
3077
3124
|
}
|
|
3078
3125
|
if ("year" in val) {
|
|
3079
|
-
return {
|
|
3126
|
+
return {
|
|
3127
|
+
id: v4_default(),
|
|
3128
|
+
key,
|
|
3129
|
+
type: "date",
|
|
3130
|
+
value: { type: "Ano", value: val.year || "" }
|
|
3131
|
+
};
|
|
3080
3132
|
}
|
|
3081
3133
|
if ("date" in val) {
|
|
3082
|
-
return {
|
|
3134
|
+
return {
|
|
3135
|
+
id: v4_default(),
|
|
3136
|
+
key,
|
|
3137
|
+
type: "date",
|
|
3138
|
+
value: { type: "Data", value: val.date || "" }
|
|
3139
|
+
};
|
|
3083
3140
|
}
|
|
3084
3141
|
}
|
|
3085
|
-
return {
|
|
3142
|
+
return {
|
|
3143
|
+
id: v4_default(),
|
|
3144
|
+
key,
|
|
3145
|
+
type: "date",
|
|
3146
|
+
value: { type: "Data", value: "" }
|
|
3147
|
+
};
|
|
3086
3148
|
}
|
|
3087
3149
|
if (t === "list" || t === "links" || t === "images" || t === "documents") {
|
|
3088
3150
|
const safeList = (val || []).map((item) => ({
|
|
@@ -3092,7 +3154,12 @@ function extractCustomPropsFromNode(node) {
|
|
|
3092
3154
|
}));
|
|
3093
3155
|
return { id: v4_default(), key, type: t, value: safeList };
|
|
3094
3156
|
}
|
|
3095
|
-
return {
|
|
3157
|
+
return {
|
|
3158
|
+
id: v4_default(),
|
|
3159
|
+
key,
|
|
3160
|
+
type: t,
|
|
3161
|
+
value: t === "number" ? Number(val) || 0 : String(val ?? "")
|
|
3162
|
+
};
|
|
3096
3163
|
});
|
|
3097
3164
|
}
|
|
3098
3165
|
function toObjectFromCustomProps(customProps) {
|
|
@@ -3107,7 +3174,12 @@ function toObjectFromCustomProps(customProps) {
|
|
|
3107
3174
|
const { type: uiDateType, ...dateValues } = p.value || {};
|
|
3108
3175
|
if (uiDateType) {
|
|
3109
3176
|
if (uiDateType === "Date Interval") {
|
|
3110
|
-
out[key] = {
|
|
3177
|
+
out[key] = {
|
|
3178
|
+
date_interval: {
|
|
3179
|
+
start: dateValues.start || "",
|
|
3180
|
+
end: dateValues.end || ""
|
|
3181
|
+
}
|
|
3182
|
+
};
|
|
3111
3183
|
} else if (uiDateType === "Ano") {
|
|
3112
3184
|
out[key] = { year: dateValues.value || "" };
|
|
3113
3185
|
} else {
|
|
@@ -3143,10 +3215,20 @@ function createTextSprite(text, fontSize = 64) {
|
|
|
3143
3215
|
context.fillText(effectiveText, canvas.width / 2, canvas.height / 2);
|
|
3144
3216
|
const texture = new THREE2.CanvasTexture(canvas);
|
|
3145
3217
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
3146
|
-
const spriteMaterial = new THREE2.SpriteMaterial({
|
|
3218
|
+
const spriteMaterial = new THREE2.SpriteMaterial({
|
|
3219
|
+
map: texture,
|
|
3220
|
+
sizeAttenuation: true,
|
|
3221
|
+
depthWrite: false,
|
|
3222
|
+
transparent: true,
|
|
3223
|
+
toneMapped: false
|
|
3224
|
+
});
|
|
3147
3225
|
const sprite = new THREE2.Sprite(spriteMaterial);
|
|
3148
3226
|
const scaleFactor = 0.05;
|
|
3149
|
-
sprite.scale.set(
|
|
3227
|
+
sprite.scale.set(
|
|
3228
|
+
canvas.width * scaleFactor,
|
|
3229
|
+
canvas.height * scaleFactor,
|
|
3230
|
+
1
|
|
3231
|
+
);
|
|
3150
3232
|
sprite.layers.set(DEFAULT_LAYER);
|
|
3151
3233
|
return sprite;
|
|
3152
3234
|
}
|
|
@@ -3162,7 +3244,14 @@ function makeGlowTexture() {
|
|
|
3162
3244
|
const canvas = document.createElement("canvas");
|
|
3163
3245
|
canvas.width = canvas.height = size;
|
|
3164
3246
|
const ctx = canvas.getContext("2d");
|
|
3165
|
-
const grd = ctx.createRadialGradient(
|
|
3247
|
+
const grd = ctx.createRadialGradient(
|
|
3248
|
+
size / 2,
|
|
3249
|
+
size / 2,
|
|
3250
|
+
0,
|
|
3251
|
+
size / 2,
|
|
3252
|
+
size / 2,
|
|
3253
|
+
size / 2
|
|
3254
|
+
);
|
|
3166
3255
|
grd.addColorStop(0, "rgba(255,255,255,1)");
|
|
3167
3256
|
grd.addColorStop(0.4, "rgba(255,255,255,0.45)");
|
|
3168
3257
|
grd.addColorStop(1, "rgba(255,255,255,0)");
|
|
@@ -3178,8 +3267,19 @@ function addGlowAura(mesh, hexColor, glowTexture, auraScale) {
|
|
|
3178
3267
|
let midBoost = 1 - Math.abs(L - 0.5) * 2;
|
|
3179
3268
|
midBoost = THREE2.MathUtils.clamp(midBoost, 0, 1);
|
|
3180
3269
|
const auraOpacity = THREE2.MathUtils.lerp(0.25, 0.8, midBoost);
|
|
3181
|
-
const auraColor = new THREE2.Color(hexColor).lerp(
|
|
3182
|
-
|
|
3270
|
+
const auraColor = new THREE2.Color(hexColor).lerp(
|
|
3271
|
+
new THREE2.Color("#ffffff"),
|
|
3272
|
+
0.25
|
|
3273
|
+
);
|
|
3274
|
+
const auraMat = new THREE2.SpriteMaterial({
|
|
3275
|
+
map: glowTexture,
|
|
3276
|
+
color: auraColor,
|
|
3277
|
+
opacity: auraOpacity,
|
|
3278
|
+
blending: THREE2.AdditiveBlending,
|
|
3279
|
+
transparent: true,
|
|
3280
|
+
depthWrite: false,
|
|
3281
|
+
toneMapped: false
|
|
3282
|
+
});
|
|
3183
3283
|
const aura = new THREE2.Sprite(auraMat);
|
|
3184
3284
|
aura.scale.setScalar(auraScale);
|
|
3185
3285
|
aura.name = "aura";
|
|
@@ -3212,7 +3312,16 @@ function calculateNodePositions(nodes) {
|
|
|
3212
3312
|
}
|
|
3213
3313
|
return positions;
|
|
3214
3314
|
}
|
|
3215
|
-
function updateTooltip({
|
|
3315
|
+
function updateTooltip({
|
|
3316
|
+
tooltipEl,
|
|
3317
|
+
hoveredNode,
|
|
3318
|
+
hoveredLink,
|
|
3319
|
+
camera,
|
|
3320
|
+
mountEl,
|
|
3321
|
+
isSceneBusy,
|
|
3322
|
+
parentData,
|
|
3323
|
+
ancestryData
|
|
3324
|
+
}) {
|
|
3216
3325
|
var _a, _b;
|
|
3217
3326
|
if (!tooltipEl || !camera || !mountEl) return;
|
|
3218
3327
|
let content = "";
|
|
@@ -3223,7 +3332,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3223
3332
|
currentId = `node_${hoveredNode.userData.id}`;
|
|
3224
3333
|
positionTarget = hoveredNode;
|
|
3225
3334
|
if (tooltipEl.dataset.currentId !== currentId) {
|
|
3226
|
-
content = generateTooltipHtml(
|
|
3335
|
+
content = generateTooltipHtml(
|
|
3336
|
+
hoveredNode.userData,
|
|
3337
|
+
parentData,
|
|
3338
|
+
ancestryData
|
|
3339
|
+
);
|
|
3227
3340
|
}
|
|
3228
3341
|
} else if (hoveredLink && !isSceneBusy) {
|
|
3229
3342
|
const linkData = hoveredLink.userData.isAncestryLink ? hoveredLink.userData.relationship || {} : hoveredLink.userData;
|
|
@@ -3233,9 +3346,16 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3233
3346
|
if (hoveredLink.userData.isCurved) {
|
|
3234
3347
|
const positions = hoveredLink.geometry.attributes.position.array;
|
|
3235
3348
|
const midIndex = Math.floor(positions.length / 2 / 3) * 3;
|
|
3236
|
-
positionTarget = new THREE2.Vector3(
|
|
3349
|
+
positionTarget = new THREE2.Vector3(
|
|
3350
|
+
positions[midIndex],
|
|
3351
|
+
positions[midIndex + 1],
|
|
3352
|
+
positions[midIndex + 2]
|
|
3353
|
+
);
|
|
3237
3354
|
} else {
|
|
3238
|
-
positionTarget = new THREE2.Vector3().addVectors(
|
|
3355
|
+
positionTarget = new THREE2.Vector3().addVectors(
|
|
3356
|
+
hoveredLink.userData.sourceNode.position,
|
|
3357
|
+
hoveredLink.userData.targetNode.position
|
|
3358
|
+
).multiplyScalar(0.5);
|
|
3239
3359
|
}
|
|
3240
3360
|
isLink = true;
|
|
3241
3361
|
if (tooltipEl.dataset.currentId !== currentId) {
|
|
@@ -3264,9 +3384,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3264
3384
|
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
3265
3385
|
const offsetX = 20;
|
|
3266
3386
|
const offsetY = 20;
|
|
3267
|
-
if (x + tooltipRect.width + offsetX > clientWidth)
|
|
3387
|
+
if (x + tooltipRect.width + offsetX > clientWidth)
|
|
3388
|
+
x = x - tooltipRect.width - offsetX;
|
|
3268
3389
|
else x = x + offsetX;
|
|
3269
|
-
if (y + tooltipRect.height + offsetY > clientHeight)
|
|
3390
|
+
if (y + tooltipRect.height + offsetY > clientHeight)
|
|
3391
|
+
y = y - tooltipRect.height - offsetY;
|
|
3270
3392
|
else y = y + offsetY;
|
|
3271
3393
|
tooltipEl.style.display = "block";
|
|
3272
3394
|
tooltipEl.style.left = `${x}px`;
|
|
@@ -3300,7 +3422,9 @@ var processDescriptionForSave = (text, existingSections = []) => {
|
|
|
3300
3422
|
const content = parts[i + 2] || "";
|
|
3301
3423
|
let finalUuid = null;
|
|
3302
3424
|
if (suffix) {
|
|
3303
|
-
const existingMatch = existingSections.find(
|
|
3425
|
+
const existingMatch = existingSections.find(
|
|
3426
|
+
(s) => s.id && s.id.includes(suffix)
|
|
3427
|
+
);
|
|
3304
3428
|
if (existingMatch) {
|
|
3305
3429
|
finalUuid = existingMatch.id;
|
|
3306
3430
|
} else {
|
|
@@ -3391,28 +3515,34 @@ var extractFileUrlsFromProperties = (dataObject) => {
|
|
|
3391
3515
|
function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
|
|
3392
3516
|
const [width, setWidth] = (0, import_react3.useState)(initialWidth);
|
|
3393
3517
|
const [isResizing, setIsResizing] = (0, import_react3.useState)(false);
|
|
3394
|
-
const handlePointerDown = (0, import_react3.useCallback)(
|
|
3395
|
-
e
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
const
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3518
|
+
const handlePointerDown = (0, import_react3.useCallback)(
|
|
3519
|
+
(e) => {
|
|
3520
|
+
e.preventDefault();
|
|
3521
|
+
e.stopPropagation();
|
|
3522
|
+
setIsResizing(true);
|
|
3523
|
+
const startX = e.clientX;
|
|
3524
|
+
const startWidth = width;
|
|
3525
|
+
const originalUserSelect = document.body.style.userSelect;
|
|
3526
|
+
document.body.style.userSelect = "none";
|
|
3527
|
+
const handlePointerMove = (moveEvent) => {
|
|
3528
|
+
const deltaX = startX - moveEvent.clientX;
|
|
3529
|
+
const newWidth = Math.min(
|
|
3530
|
+
Math.max(startWidth + deltaX, minWidth),
|
|
3531
|
+
maxWidth
|
|
3532
|
+
);
|
|
3533
|
+
setWidth(newWidth);
|
|
3534
|
+
};
|
|
3535
|
+
const handlePointerUp = () => {
|
|
3536
|
+
setIsResizing(false);
|
|
3537
|
+
document.body.style.userSelect = originalUserSelect;
|
|
3538
|
+
document.removeEventListener("pointermove", handlePointerMove);
|
|
3539
|
+
document.removeEventListener("pointerup", handlePointerUp);
|
|
3540
|
+
};
|
|
3541
|
+
document.addEventListener("pointermove", handlePointerMove);
|
|
3542
|
+
document.addEventListener("pointerup", handlePointerUp);
|
|
3543
|
+
},
|
|
3544
|
+
[width, minWidth, maxWidth]
|
|
3545
|
+
);
|
|
3416
3546
|
return { width, isResizing, handlePointerDown, setWidth };
|
|
3417
3547
|
}
|
|
3418
3548
|
|
package/dist/index.mjs
CHANGED
|
@@ -2842,18 +2842,27 @@ function createNewCustomProperty(existingProps = []) {
|
|
|
2842
2842
|
};
|
|
2843
2843
|
}
|
|
2844
2844
|
var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
|
|
2845
|
-
const match = refString.match(
|
|
2845
|
+
const match = refString.match(
|
|
2846
|
+
/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/
|
|
2847
|
+
);
|
|
2846
2848
|
if (!match) return null;
|
|
2847
2849
|
const [_, type, itemId, sectionId] = match;
|
|
2848
2850
|
let sourceItem = null;
|
|
2849
2851
|
if (type === "node") {
|
|
2850
2852
|
sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
|
|
2851
2853
|
} else {
|
|
2852
|
-
sourceItem = availableAncestries.find(
|
|
2854
|
+
sourceItem = availableAncestries.find(
|
|
2855
|
+
(a) => String(a.ancestry_id) === String(itemId)
|
|
2856
|
+
);
|
|
2853
2857
|
}
|
|
2854
2858
|
if (!sourceItem) return null;
|
|
2855
|
-
const sections = parseDescriptionSections(
|
|
2856
|
-
|
|
2859
|
+
const sections = parseDescriptionSections(
|
|
2860
|
+
sourceItem.description,
|
|
2861
|
+
sourceItem.description_sections
|
|
2862
|
+
);
|
|
2863
|
+
const targetSection = sections.find(
|
|
2864
|
+
(s) => String(s.id) === String(sectionId)
|
|
2865
|
+
);
|
|
2857
2866
|
if (!targetSection) return null;
|
|
2858
2867
|
return {
|
|
2859
2868
|
content: targetSection.content,
|
|
@@ -2867,21 +2876,34 @@ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
|
2867
2876
|
let text = rawText;
|
|
2868
2877
|
const allNodes = parentData ? Object.values(parentData).flatMap((f) => f.nodes || []) : [];
|
|
2869
2878
|
const allAncestries = ancestryData || [];
|
|
2870
|
-
text = text.replace(
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2879
|
+
text = text.replace(
|
|
2880
|
+
/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g,
|
|
2881
|
+
(match, type, itemId, sectionId) => {
|
|
2882
|
+
const resolved = resolveDescriptionReference(
|
|
2883
|
+
match,
|
|
2884
|
+
allNodes,
|
|
2885
|
+
allAncestries
|
|
2886
|
+
);
|
|
2887
|
+
if (resolved && !resolved.error) {
|
|
2888
|
+
return resolved.content;
|
|
2889
|
+
}
|
|
2890
|
+
return "[Refer\xEAncia indispon\xEDvel]";
|
|
2874
2891
|
}
|
|
2875
|
-
|
|
2876
|
-
});
|
|
2892
|
+
);
|
|
2877
2893
|
text = text.replace(/\*\/\s*\d+(?::[a-zA-Z0-9-]+)?\s*\//g, "");
|
|
2878
|
-
text = text.replace(
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2894
|
+
text = text.replace(
|
|
2895
|
+
/\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g,
|
|
2896
|
+
(match, nodeId) => {
|
|
2897
|
+
const node = allNodes.find((n) => String(n.id) === String(nodeId));
|
|
2898
|
+
return node ? `@${node.name}` : `@Men\xE7\xE3o`;
|
|
2899
|
+
}
|
|
2900
|
+
);
|
|
2901
|
+
text = text.replace(
|
|
2902
|
+
/\[\[MENTION:image:([^|\]]+)\|?([^\]]*)\]\]/g,
|
|
2903
|
+
(match, url, name) => {
|
|
2904
|
+
return name ? `[Imagem: ${name}]` : `[Imagem]`;
|
|
2905
|
+
}
|
|
2906
|
+
);
|
|
2885
2907
|
text = text.replace(/^#+\s*/gm, "");
|
|
2886
2908
|
text = text.replace(/```[\s\S]*?```/g, "[C\xF3digo]");
|
|
2887
2909
|
text = text.replace(/-\s\[[xX ]\]\s*/g, "\u2022 ");
|
|
@@ -2889,7 +2911,14 @@ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
|
2889
2911
|
return text.trim();
|
|
2890
2912
|
}
|
|
2891
2913
|
function generateTooltipHtml(data, parentData, ancestryData) {
|
|
2892
|
-
const ignoredKeys = [
|
|
2914
|
+
const ignoredKeys = [
|
|
2915
|
+
"id",
|
|
2916
|
+
"name",
|
|
2917
|
+
"type",
|
|
2918
|
+
"color",
|
|
2919
|
+
"_baseEmissiveIntensity",
|
|
2920
|
+
"description"
|
|
2921
|
+
];
|
|
2893
2922
|
const customKeys = Object.keys(data).filter((k) => !ignoredKeys.includes(k));
|
|
2894
2923
|
const extras = customKeys.length;
|
|
2895
2924
|
let typeDisplay = "Node";
|
|
@@ -2904,7 +2933,11 @@ function generateTooltipHtml(data, parentData, ancestryData) {
|
|
|
2904
2933
|
<div style="font-weight:600; font-size: 14px; color: #fff;">${typeDisplay}</div>
|
|
2905
2934
|
<div style="margin-bottom: 2px; color: #e2e8f0;">${data.name || ""}</div>`;
|
|
2906
2935
|
if (data.description) {
|
|
2907
|
-
const cleanDesc = formatDescriptionForTooltip(
|
|
2936
|
+
const cleanDesc = formatDescriptionForTooltip(
|
|
2937
|
+
data.description,
|
|
2938
|
+
parentData,
|
|
2939
|
+
ancestryData
|
|
2940
|
+
);
|
|
2908
2941
|
if (cleanDesc) {
|
|
2909
2942
|
html += `<div style="
|
|
2910
2943
|
margin-top: 6px;
|
|
@@ -2942,7 +2975,11 @@ function generateLinkTooltipHtml(data, parentData, ancestryData) {
|
|
|
2942
2975
|
html += `<div style="font-weight:600; font-size: 14px; color: #a5f3fc; margin-bottom: 4px;">${data.name}</div>`;
|
|
2943
2976
|
}
|
|
2944
2977
|
if (hasDescription) {
|
|
2945
|
-
const cleanDesc = formatDescriptionForTooltip(
|
|
2978
|
+
const cleanDesc = formatDescriptionForTooltip(
|
|
2979
|
+
data.description,
|
|
2980
|
+
parentData,
|
|
2981
|
+
ancestryData
|
|
2982
|
+
);
|
|
2946
2983
|
if (cleanDesc) {
|
|
2947
2984
|
html += `<div style="
|
|
2948
2985
|
display: -webkit-box;
|
|
@@ -3024,7 +3061,8 @@ var IGNORED_KEYS = [
|
|
|
3024
3061
|
"isAddingAbstractionNodes",
|
|
3025
3062
|
"status",
|
|
3026
3063
|
"is_quest",
|
|
3027
|
-
"raw_title"
|
|
3064
|
+
"raw_title",
|
|
3065
|
+
"assignee_id"
|
|
3028
3066
|
];
|
|
3029
3067
|
function extractCustomPropsFromNode(node) {
|
|
3030
3068
|
const customPropTypes = node._customPropTypes || {};
|
|
@@ -3034,16 +3072,40 @@ function extractCustomPropsFromNode(node) {
|
|
|
3034
3072
|
if (t === "date") {
|
|
3035
3073
|
if (val && typeof val === "object") {
|
|
3036
3074
|
if ("date_interval" in val) {
|
|
3037
|
-
return {
|
|
3075
|
+
return {
|
|
3076
|
+
id: v4_default(),
|
|
3077
|
+
key,
|
|
3078
|
+
type: "date",
|
|
3079
|
+
value: {
|
|
3080
|
+
type: "Date Interval",
|
|
3081
|
+
start: val.date_interval.start || "",
|
|
3082
|
+
end: val.date_interval.end || ""
|
|
3083
|
+
}
|
|
3084
|
+
};
|
|
3038
3085
|
}
|
|
3039
3086
|
if ("year" in val) {
|
|
3040
|
-
return {
|
|
3087
|
+
return {
|
|
3088
|
+
id: v4_default(),
|
|
3089
|
+
key,
|
|
3090
|
+
type: "date",
|
|
3091
|
+
value: { type: "Ano", value: val.year || "" }
|
|
3092
|
+
};
|
|
3041
3093
|
}
|
|
3042
3094
|
if ("date" in val) {
|
|
3043
|
-
return {
|
|
3095
|
+
return {
|
|
3096
|
+
id: v4_default(),
|
|
3097
|
+
key,
|
|
3098
|
+
type: "date",
|
|
3099
|
+
value: { type: "Data", value: val.date || "" }
|
|
3100
|
+
};
|
|
3044
3101
|
}
|
|
3045
3102
|
}
|
|
3046
|
-
return {
|
|
3103
|
+
return {
|
|
3104
|
+
id: v4_default(),
|
|
3105
|
+
key,
|
|
3106
|
+
type: "date",
|
|
3107
|
+
value: { type: "Data", value: "" }
|
|
3108
|
+
};
|
|
3047
3109
|
}
|
|
3048
3110
|
if (t === "list" || t === "links" || t === "images" || t === "documents") {
|
|
3049
3111
|
const safeList = (val || []).map((item) => ({
|
|
@@ -3053,7 +3115,12 @@ function extractCustomPropsFromNode(node) {
|
|
|
3053
3115
|
}));
|
|
3054
3116
|
return { id: v4_default(), key, type: t, value: safeList };
|
|
3055
3117
|
}
|
|
3056
|
-
return {
|
|
3118
|
+
return {
|
|
3119
|
+
id: v4_default(),
|
|
3120
|
+
key,
|
|
3121
|
+
type: t,
|
|
3122
|
+
value: t === "number" ? Number(val) || 0 : String(val ?? "")
|
|
3123
|
+
};
|
|
3057
3124
|
});
|
|
3058
3125
|
}
|
|
3059
3126
|
function toObjectFromCustomProps(customProps) {
|
|
@@ -3068,7 +3135,12 @@ function toObjectFromCustomProps(customProps) {
|
|
|
3068
3135
|
const { type: uiDateType, ...dateValues } = p.value || {};
|
|
3069
3136
|
if (uiDateType) {
|
|
3070
3137
|
if (uiDateType === "Date Interval") {
|
|
3071
|
-
out[key] = {
|
|
3138
|
+
out[key] = {
|
|
3139
|
+
date_interval: {
|
|
3140
|
+
start: dateValues.start || "",
|
|
3141
|
+
end: dateValues.end || ""
|
|
3142
|
+
}
|
|
3143
|
+
};
|
|
3072
3144
|
} else if (uiDateType === "Ano") {
|
|
3073
3145
|
out[key] = { year: dateValues.value || "" };
|
|
3074
3146
|
} else {
|
|
@@ -3104,10 +3176,20 @@ function createTextSprite(text, fontSize = 64) {
|
|
|
3104
3176
|
context.fillText(effectiveText, canvas.width / 2, canvas.height / 2);
|
|
3105
3177
|
const texture = new THREE2.CanvasTexture(canvas);
|
|
3106
3178
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
3107
|
-
const spriteMaterial = new THREE2.SpriteMaterial({
|
|
3179
|
+
const spriteMaterial = new THREE2.SpriteMaterial({
|
|
3180
|
+
map: texture,
|
|
3181
|
+
sizeAttenuation: true,
|
|
3182
|
+
depthWrite: false,
|
|
3183
|
+
transparent: true,
|
|
3184
|
+
toneMapped: false
|
|
3185
|
+
});
|
|
3108
3186
|
const sprite = new THREE2.Sprite(spriteMaterial);
|
|
3109
3187
|
const scaleFactor = 0.05;
|
|
3110
|
-
sprite.scale.set(
|
|
3188
|
+
sprite.scale.set(
|
|
3189
|
+
canvas.width * scaleFactor,
|
|
3190
|
+
canvas.height * scaleFactor,
|
|
3191
|
+
1
|
|
3192
|
+
);
|
|
3111
3193
|
sprite.layers.set(DEFAULT_LAYER);
|
|
3112
3194
|
return sprite;
|
|
3113
3195
|
}
|
|
@@ -3123,7 +3205,14 @@ function makeGlowTexture() {
|
|
|
3123
3205
|
const canvas = document.createElement("canvas");
|
|
3124
3206
|
canvas.width = canvas.height = size;
|
|
3125
3207
|
const ctx = canvas.getContext("2d");
|
|
3126
|
-
const grd = ctx.createRadialGradient(
|
|
3208
|
+
const grd = ctx.createRadialGradient(
|
|
3209
|
+
size / 2,
|
|
3210
|
+
size / 2,
|
|
3211
|
+
0,
|
|
3212
|
+
size / 2,
|
|
3213
|
+
size / 2,
|
|
3214
|
+
size / 2
|
|
3215
|
+
);
|
|
3127
3216
|
grd.addColorStop(0, "rgba(255,255,255,1)");
|
|
3128
3217
|
grd.addColorStop(0.4, "rgba(255,255,255,0.45)");
|
|
3129
3218
|
grd.addColorStop(1, "rgba(255,255,255,0)");
|
|
@@ -3139,8 +3228,19 @@ function addGlowAura(mesh, hexColor, glowTexture, auraScale) {
|
|
|
3139
3228
|
let midBoost = 1 - Math.abs(L - 0.5) * 2;
|
|
3140
3229
|
midBoost = THREE2.MathUtils.clamp(midBoost, 0, 1);
|
|
3141
3230
|
const auraOpacity = THREE2.MathUtils.lerp(0.25, 0.8, midBoost);
|
|
3142
|
-
const auraColor = new THREE2.Color(hexColor).lerp(
|
|
3143
|
-
|
|
3231
|
+
const auraColor = new THREE2.Color(hexColor).lerp(
|
|
3232
|
+
new THREE2.Color("#ffffff"),
|
|
3233
|
+
0.25
|
|
3234
|
+
);
|
|
3235
|
+
const auraMat = new THREE2.SpriteMaterial({
|
|
3236
|
+
map: glowTexture,
|
|
3237
|
+
color: auraColor,
|
|
3238
|
+
opacity: auraOpacity,
|
|
3239
|
+
blending: THREE2.AdditiveBlending,
|
|
3240
|
+
transparent: true,
|
|
3241
|
+
depthWrite: false,
|
|
3242
|
+
toneMapped: false
|
|
3243
|
+
});
|
|
3144
3244
|
const aura = new THREE2.Sprite(auraMat);
|
|
3145
3245
|
aura.scale.setScalar(auraScale);
|
|
3146
3246
|
aura.name = "aura";
|
|
@@ -3173,7 +3273,16 @@ function calculateNodePositions(nodes) {
|
|
|
3173
3273
|
}
|
|
3174
3274
|
return positions;
|
|
3175
3275
|
}
|
|
3176
|
-
function updateTooltip({
|
|
3276
|
+
function updateTooltip({
|
|
3277
|
+
tooltipEl,
|
|
3278
|
+
hoveredNode,
|
|
3279
|
+
hoveredLink,
|
|
3280
|
+
camera,
|
|
3281
|
+
mountEl,
|
|
3282
|
+
isSceneBusy,
|
|
3283
|
+
parentData,
|
|
3284
|
+
ancestryData
|
|
3285
|
+
}) {
|
|
3177
3286
|
var _a, _b;
|
|
3178
3287
|
if (!tooltipEl || !camera || !mountEl) return;
|
|
3179
3288
|
let content = "";
|
|
@@ -3184,7 +3293,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3184
3293
|
currentId = `node_${hoveredNode.userData.id}`;
|
|
3185
3294
|
positionTarget = hoveredNode;
|
|
3186
3295
|
if (tooltipEl.dataset.currentId !== currentId) {
|
|
3187
|
-
content = generateTooltipHtml(
|
|
3296
|
+
content = generateTooltipHtml(
|
|
3297
|
+
hoveredNode.userData,
|
|
3298
|
+
parentData,
|
|
3299
|
+
ancestryData
|
|
3300
|
+
);
|
|
3188
3301
|
}
|
|
3189
3302
|
} else if (hoveredLink && !isSceneBusy) {
|
|
3190
3303
|
const linkData = hoveredLink.userData.isAncestryLink ? hoveredLink.userData.relationship || {} : hoveredLink.userData;
|
|
@@ -3194,9 +3307,16 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3194
3307
|
if (hoveredLink.userData.isCurved) {
|
|
3195
3308
|
const positions = hoveredLink.geometry.attributes.position.array;
|
|
3196
3309
|
const midIndex = Math.floor(positions.length / 2 / 3) * 3;
|
|
3197
|
-
positionTarget = new THREE2.Vector3(
|
|
3310
|
+
positionTarget = new THREE2.Vector3(
|
|
3311
|
+
positions[midIndex],
|
|
3312
|
+
positions[midIndex + 1],
|
|
3313
|
+
positions[midIndex + 2]
|
|
3314
|
+
);
|
|
3198
3315
|
} else {
|
|
3199
|
-
positionTarget = new THREE2.Vector3().addVectors(
|
|
3316
|
+
positionTarget = new THREE2.Vector3().addVectors(
|
|
3317
|
+
hoveredLink.userData.sourceNode.position,
|
|
3318
|
+
hoveredLink.userData.targetNode.position
|
|
3319
|
+
).multiplyScalar(0.5);
|
|
3200
3320
|
}
|
|
3201
3321
|
isLink = true;
|
|
3202
3322
|
if (tooltipEl.dataset.currentId !== currentId) {
|
|
@@ -3225,9 +3345,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3225
3345
|
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
3226
3346
|
const offsetX = 20;
|
|
3227
3347
|
const offsetY = 20;
|
|
3228
|
-
if (x + tooltipRect.width + offsetX > clientWidth)
|
|
3348
|
+
if (x + tooltipRect.width + offsetX > clientWidth)
|
|
3349
|
+
x = x - tooltipRect.width - offsetX;
|
|
3229
3350
|
else x = x + offsetX;
|
|
3230
|
-
if (y + tooltipRect.height + offsetY > clientHeight)
|
|
3351
|
+
if (y + tooltipRect.height + offsetY > clientHeight)
|
|
3352
|
+
y = y - tooltipRect.height - offsetY;
|
|
3231
3353
|
else y = y + offsetY;
|
|
3232
3354
|
tooltipEl.style.display = "block";
|
|
3233
3355
|
tooltipEl.style.left = `${x}px`;
|
|
@@ -3261,7 +3383,9 @@ var processDescriptionForSave = (text, existingSections = []) => {
|
|
|
3261
3383
|
const content = parts[i + 2] || "";
|
|
3262
3384
|
let finalUuid = null;
|
|
3263
3385
|
if (suffix) {
|
|
3264
|
-
const existingMatch = existingSections.find(
|
|
3386
|
+
const existingMatch = existingSections.find(
|
|
3387
|
+
(s) => s.id && s.id.includes(suffix)
|
|
3388
|
+
);
|
|
3265
3389
|
if (existingMatch) {
|
|
3266
3390
|
finalUuid = existingMatch.id;
|
|
3267
3391
|
} else {
|
|
@@ -3352,28 +3476,34 @@ var extractFileUrlsFromProperties = (dataObject) => {
|
|
|
3352
3476
|
function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
|
|
3353
3477
|
const [width, setWidth] = useState3(initialWidth);
|
|
3354
3478
|
const [isResizing, setIsResizing] = useState3(false);
|
|
3355
|
-
const handlePointerDown = useCallback(
|
|
3356
|
-
e
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
const
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3479
|
+
const handlePointerDown = useCallback(
|
|
3480
|
+
(e) => {
|
|
3481
|
+
e.preventDefault();
|
|
3482
|
+
e.stopPropagation();
|
|
3483
|
+
setIsResizing(true);
|
|
3484
|
+
const startX = e.clientX;
|
|
3485
|
+
const startWidth = width;
|
|
3486
|
+
const originalUserSelect = document.body.style.userSelect;
|
|
3487
|
+
document.body.style.userSelect = "none";
|
|
3488
|
+
const handlePointerMove = (moveEvent) => {
|
|
3489
|
+
const deltaX = startX - moveEvent.clientX;
|
|
3490
|
+
const newWidth = Math.min(
|
|
3491
|
+
Math.max(startWidth + deltaX, minWidth),
|
|
3492
|
+
maxWidth
|
|
3493
|
+
);
|
|
3494
|
+
setWidth(newWidth);
|
|
3495
|
+
};
|
|
3496
|
+
const handlePointerUp = () => {
|
|
3497
|
+
setIsResizing(false);
|
|
3498
|
+
document.body.style.userSelect = originalUserSelect;
|
|
3499
|
+
document.removeEventListener("pointermove", handlePointerMove);
|
|
3500
|
+
document.removeEventListener("pointerup", handlePointerUp);
|
|
3501
|
+
};
|
|
3502
|
+
document.addEventListener("pointermove", handlePointerMove);
|
|
3503
|
+
document.addEventListener("pointerup", handlePointerUp);
|
|
3504
|
+
},
|
|
3505
|
+
[width, minWidth, maxWidth]
|
|
3506
|
+
);
|
|
3377
3507
|
return { width, isResizing, handlePointerDown, setWidth };
|
|
3378
3508
|
}
|
|
3379
3509
|
|
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.
|
|
3
|
+
"version": "1.2.5-dev.15",
|
|
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",
|