@tnkrai/tnkr-editor 0.1.9 → 0.2.0
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.cjs +240 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +240 -57
- package/dist/index.js.map +1 -1
- package/dist/preview/TnkrPreview.d.ts.map +1 -1
- package/dist/src/components/TnkrModelView/TnkrEditorModelViewCore.d.ts +2 -0
- package/dist/src/components/TnkrModelView/TnkrEditorModelViewCore.d.ts.map +1 -1
- package/dist/src/components/assembly/AssemblyAnnotationsOverlay.d.ts.map +1 -1
- package/dist/src/components/assembly/AssemblyViewMode.d.ts +3 -0
- package/dist/src/components/assembly/AssemblyViewMode.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -74793,7 +74793,9 @@ const PartContextMenu = ({ contextMenu, onClose, onHighlight, onRemoveHighlight,
|
|
|
74793
74793
|
|
|
74794
74794
|
const TnkrEditorModelViewCore = ({ htmlString, className, style, onElementsReady,
|
|
74795
74795
|
// Accept all dependencies as props instead of using hooks
|
|
74796
|
-
parts, phases = [], selectedPhaseId, selectedStepId, selectStep, isAnimating = false, isPreparingAnimation = false, setIsAnimating, setIsPreparingAnimation,
|
|
74796
|
+
parts, phases = [], selectedPhaseId, selectedStepId, selectStep, isAnimating = false, isPreparingAnimation = false, setIsAnimating, setIsPreparingAnimation,
|
|
74797
|
+
// Navigation handlers from parent
|
|
74798
|
+
handleNext: parentHandleNext, handlePrevious: parentHandlePrevious, }) => {
|
|
74797
74799
|
// Use the hook with parts passed as parameter
|
|
74798
74800
|
const { containerRef, scriptsLoaded, initializeModel, controlFunctions, partOperations, handleShowAllParts, updateExplosion, updateDirectionalExplosion, setCameraSettings, contextMenu, setContextMenu, handleContextMenuHighlight, handleContextMenuRemoveHighlight, handleContextMenuHide, handleContextMenuShow, handleContextMenuIsolate, isPartHighlighted, isPartHidden, isPartIsolated, } = useModelViewCore(parts);
|
|
74799
74801
|
const [lastStepId, setLastStepId] = React.useState(null);
|
|
@@ -74844,31 +74846,49 @@ parts, phases = [], selectedPhaseId, selectedStepId, selectStep, isAnimating = f
|
|
|
74844
74846
|
});
|
|
74845
74847
|
return allSteps;
|
|
74846
74848
|
}, [phases]);
|
|
74847
|
-
//
|
|
74849
|
+
// Use parent navigation handlers if provided, otherwise create local ones as fallback
|
|
74848
74850
|
const handlePrevious = React.useCallback(() => {
|
|
74849
|
-
if (
|
|
74850
|
-
|
|
74851
|
-
|
|
74852
|
-
|
|
74853
|
-
|
|
74854
|
-
const currentIndex = allSteps.findIndex((s) => s.phaseId === selectedPhaseId && s.stepId === selectedStepId);
|
|
74855
|
-
if (currentIndex > 0) {
|
|
74856
|
-
const prevStep = allSteps[currentIndex - 1];
|
|
74857
|
-
selectStep(prevStep.phaseId, prevStep.stepId);
|
|
74851
|
+
if (parentHandlePrevious) {
|
|
74852
|
+
// Check animation state before calling parent handler
|
|
74853
|
+
if (isAnimatingRef.current || isPreparingRef.current)
|
|
74854
|
+
return;
|
|
74855
|
+
parentHandlePrevious();
|
|
74858
74856
|
}
|
|
74859
|
-
|
|
74857
|
+
else {
|
|
74858
|
+
// Fallback to local implementation for backward compatibility
|
|
74859
|
+
if (!selectStep || !selectedPhaseId || !selectedStepId)
|
|
74860
|
+
return;
|
|
74861
|
+
if (isAnimatingRef.current || isPreparingRef.current)
|
|
74862
|
+
return;
|
|
74863
|
+
const allSteps = getAllSteps();
|
|
74864
|
+
const currentIndex = allSteps.findIndex((s) => s.phaseId === selectedPhaseId && s.stepId === selectedStepId);
|
|
74865
|
+
if (currentIndex > 0) {
|
|
74866
|
+
const prevStep = allSteps[currentIndex - 1];
|
|
74867
|
+
selectStep(prevStep.phaseId, prevStep.stepId);
|
|
74868
|
+
}
|
|
74869
|
+
}
|
|
74870
|
+
}, [parentHandlePrevious, selectStep, selectedPhaseId, selectedStepId, getAllSteps]);
|
|
74860
74871
|
const handleNext = React.useCallback(() => {
|
|
74861
|
-
if (
|
|
74862
|
-
|
|
74863
|
-
|
|
74864
|
-
|
|
74865
|
-
|
|
74866
|
-
|
|
74867
|
-
|
|
74868
|
-
|
|
74869
|
-
selectStep
|
|
74872
|
+
if (parentHandleNext) {
|
|
74873
|
+
// Check animation state before calling parent handler
|
|
74874
|
+
if (isAnimatingRef.current || isPreparingRef.current)
|
|
74875
|
+
return;
|
|
74876
|
+
parentHandleNext();
|
|
74877
|
+
}
|
|
74878
|
+
else {
|
|
74879
|
+
// Fallback to local implementation for backward compatibility
|
|
74880
|
+
if (!selectStep || !selectedPhaseId || !selectedStepId)
|
|
74881
|
+
return;
|
|
74882
|
+
if (isAnimatingRef.current || isPreparingRef.current)
|
|
74883
|
+
return;
|
|
74884
|
+
const allSteps = getAllSteps();
|
|
74885
|
+
const currentIndex = allSteps.findIndex((s) => s.phaseId === selectedPhaseId && s.stepId === selectedStepId);
|
|
74886
|
+
if (currentIndex >= 0 && currentIndex < allSteps.length - 1) {
|
|
74887
|
+
const nextStep = allSteps[currentIndex + 1];
|
|
74888
|
+
selectStep(nextStep.phaseId, nextStep.stepId);
|
|
74889
|
+
}
|
|
74870
74890
|
}
|
|
74871
|
-
}, [selectStep, selectedPhaseId, selectedStepId, getAllSteps]);
|
|
74891
|
+
}, [parentHandleNext, selectStep, selectedPhaseId, selectedStepId, getAllSteps]);
|
|
74872
74892
|
// Keep refs in sync with state
|
|
74873
74893
|
React.useEffect(() => {
|
|
74874
74894
|
isAnimatingRef.current = isAnimating;
|
|
@@ -75329,8 +75349,7 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75329
75349
|
finalX = dragPositionRef.current[annotation.id].x;
|
|
75330
75350
|
finalY = dragPositionRef.current[annotation.id].y;
|
|
75331
75351
|
}
|
|
75332
|
-
else if (annotation.customOffset &&
|
|
75333
|
-
!(annotation.customOffset.x === 0 && annotation.customOffset.y === 0)) {
|
|
75352
|
+
else if (annotation.customOffset && !(annotation.customOffset.x === 0 && annotation.customOffset.y === 0)) {
|
|
75334
75353
|
// Use custom offset if dragged - but ignore (0,0) which means no real offset
|
|
75335
75354
|
finalX = canvasPos[0] + annotation.customOffset.x;
|
|
75336
75355
|
finalY = canvasPos[1] + annotation.customOffset.y;
|
|
@@ -75424,7 +75443,7 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75424
75443
|
if (hitPoint && hitPoint.length >= 3) {
|
|
75425
75444
|
const newAnnotation = Object.assign(Object.assign({}, currentAnnotation), { worldPos: [hitPoint[0], hitPoint[1], hitPoint[2]] });
|
|
75426
75445
|
// Add to annotations list
|
|
75427
|
-
setAnnotations(prev => {
|
|
75446
|
+
setAnnotations((prev) => {
|
|
75428
75447
|
const updated = [...prev, newAnnotation];
|
|
75429
75448
|
return updated;
|
|
75430
75449
|
});
|
|
@@ -75437,7 +75456,14 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75437
75456
|
updateAnnotationPositions();
|
|
75438
75457
|
}, 100);
|
|
75439
75458
|
}
|
|
75440
|
-
}, [
|
|
75459
|
+
}, [
|
|
75460
|
+
isPlacingAnnotation,
|
|
75461
|
+
currentAnnotation,
|
|
75462
|
+
updateAnnotationPositions,
|
|
75463
|
+
setAnnotations,
|
|
75464
|
+
setCurrentAnnotation,
|
|
75465
|
+
setIsPlacingAnnotation,
|
|
75466
|
+
]);
|
|
75441
75467
|
// Set up enterFrame callback for position updates with better performance
|
|
75442
75468
|
React.useEffect(() => {
|
|
75443
75469
|
if (!runtimeRef.current || annotations.length === 0)
|
|
@@ -75521,14 +75547,27 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75521
75547
|
return;
|
|
75522
75548
|
e.preventDefault();
|
|
75523
75549
|
e.stopPropagation();
|
|
75524
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
75525
75550
|
const containerRect = (_a = overlayRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
75526
75551
|
if (!containerRect)
|
|
75527
75552
|
return;
|
|
75553
|
+
// Get the annotation element's current position from the DOM
|
|
75554
|
+
const element = document.getElementById(`assembly-annotation-${annotationId}`);
|
|
75555
|
+
if (!element)
|
|
75556
|
+
return;
|
|
75557
|
+
// Get the actual current position from the element's style (this is where it's visually positioned)
|
|
75558
|
+
const currentLeft = parseFloat(element.style.left) || 0;
|
|
75559
|
+
const currentTop = parseFloat(element.style.top) || 0;
|
|
75560
|
+
// Store the exact current position to prevent any jump
|
|
75561
|
+
dragPositionRef.current[annotationId] = {
|
|
75562
|
+
x: currentLeft,
|
|
75563
|
+
y: currentTop,
|
|
75564
|
+
};
|
|
75528
75565
|
setIsDragging(annotationId);
|
|
75566
|
+
// Calculate offset from mouse to the element's current position
|
|
75567
|
+
// This maintains the grab point during dragging
|
|
75529
75568
|
setDragOffset({
|
|
75530
|
-
x: e.clientX -
|
|
75531
|
-
y: e.clientY -
|
|
75569
|
+
x: e.clientX - containerRect.left - currentLeft,
|
|
75570
|
+
y: e.clientY - containerRect.top - currentTop,
|
|
75532
75571
|
});
|
|
75533
75572
|
// Notify parent that drag started
|
|
75534
75573
|
onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart();
|
|
@@ -75545,7 +75584,7 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75545
75584
|
const canvasPos = runtimeRef.current.calcCanvasPos(x, y, z);
|
|
75546
75585
|
if (!canvasPos)
|
|
75547
75586
|
return;
|
|
75548
|
-
// Calculate new position
|
|
75587
|
+
// Calculate new position: mouse position minus the offset gives us where the center should be
|
|
75549
75588
|
const newX = e.clientX - containerRect.left - dragOffset.x;
|
|
75550
75589
|
const newY = e.clientY - containerRect.top - dragOffset.y;
|
|
75551
75590
|
// Calculate offset from 3D anchor point
|
|
@@ -75585,7 +75624,7 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75585
75624
|
if (updatedAnnotation) {
|
|
75586
75625
|
console.log('💾 Flushing pending update for annotation', updatedAnnotation.id, {
|
|
75587
75626
|
customOffset: updatedAnnotation.customOffset,
|
|
75588
|
-
scale: updatedAnnotation.scale
|
|
75627
|
+
scale: updatedAnnotation.scale,
|
|
75589
75628
|
});
|
|
75590
75629
|
// Update state with final position
|
|
75591
75630
|
setAnnotations((prev) => prev.map((annotation) => (annotation.id === updatedAnnotation.id ? updatedAnnotation : annotation)));
|
|
@@ -75713,7 +75752,9 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75713
75752
|
return null;
|
|
75714
75753
|
}
|
|
75715
75754
|
};
|
|
75716
|
-
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("svg", { className: 'absolute inset-0 w-full h-full pointer-events-none z-10 opacity-100 transition-opacity duration-300 ease-in-out', children: [jsxRuntimeExports.jsx("defs", { children: annotations
|
|
75755
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("svg", { className: 'absolute inset-0 w-full h-full pointer-events-none z-10 opacity-100 transition-opacity duration-300 ease-in-out', children: [jsxRuntimeExports.jsx("defs", { children: annotations
|
|
75756
|
+
.filter((a) => a.type === 'arrow' && a.arrow)
|
|
75757
|
+
.map((annotation) => {
|
|
75717
75758
|
const lineColor = getColorCode(annotation.arrow.color);
|
|
75718
75759
|
const uniqueId = annotation.id;
|
|
75719
75760
|
return (jsxRuntimeExports.jsxs(React__namespace.default.Fragment, { children: [jsxRuntimeExports.jsx("marker", { id: `point-fill-${uniqueId}`, markerWidth: '10', markerHeight: '10', refX: '9', refY: '3', orient: 'auto', children: jsxRuntimeExports.jsx("polygon", { points: '0 0, 10 3, 0 6', fill: lineColor }) }), jsxRuntimeExports.jsx("marker", { id: `pointFill-${uniqueId}`, markerWidth: '10', markerHeight: '10', refX: '9', refY: '3', orient: 'auto', children: jsxRuntimeExports.jsx("polygon", { points: '0 0, 10 3, 0 6', fill: lineColor }) }), jsxRuntimeExports.jsx("marker", { id: `point-outline-${uniqueId}`, markerWidth: '10', markerHeight: '10', refX: '9', refY: '3', orient: 'auto', children: jsxRuntimeExports.jsx("polygon", { points: '0 0, 10 3, 0 6', fill: 'none', stroke: lineColor, strokeWidth: '1' }) }), jsxRuntimeExports.jsx("marker", { id: `pointOutline-${uniqueId}`, markerWidth: '10', markerHeight: '10', refX: '9', refY: '3', orient: 'auto', children: jsxRuntimeExports.jsx("polygon", { points: '0 0, 10 3, 0 6', fill: 'none', stroke: lineColor, strokeWidth: '1' }) }), jsxRuntimeExports.jsx("marker", { id: `inverse-point-${uniqueId}`, markerWidth: '10', markerHeight: '10', refX: '1', refY: '3', orient: 'auto', children: jsxRuntimeExports.jsx("polygon", { points: '10 0, 0 3, 10 6', fill: lineColor }) }), jsxRuntimeExports.jsx("marker", { id: `inversePointFill-${uniqueId}`, markerWidth: '10', markerHeight: '10', refX: '1', refY: '3', orient: 'auto', children: jsxRuntimeExports.jsx("polygon", { points: '10 0, 0 3, 10 6', fill: lineColor }) }), jsxRuntimeExports.jsx("marker", { id: `diamond-${uniqueId}`, markerWidth: '10', markerHeight: '10', refX: '5', refY: '5', orient: 'auto', children: jsxRuntimeExports.jsx("polygon", { points: '5 1, 9 5, 5 9, 1 5', fill: lineColor }) }), jsxRuntimeExports.jsx("marker", { id: `dot-${uniqueId}`, markerWidth: '8', markerHeight: '8', refX: '4', refY: '4', orient: 'auto', children: jsxRuntimeExports.jsx("circle", { cx: '4', cy: '4', r: '3', fill: lineColor }) }), jsxRuntimeExports.jsx("marker", { id: `dotFill-${uniqueId}`, markerWidth: '8', markerHeight: '8', refX: '4', refY: '4', orient: 'auto', children: jsxRuntimeExports.jsx("circle", { cx: '4', cy: '4', r: '3', fill: lineColor }) }), jsxRuntimeExports.jsx("marker", { id: `joint-${uniqueId}`, markerWidth: '8', markerHeight: '8', refX: '4', refY: '4', orient: 'auto', children: jsxRuntimeExports.jsx("circle", { cx: '4', cy: '4', r: '2', fill: 'none', stroke: lineColor, strokeWidth: '1' }) })] }, `markers-${uniqueId}`));
|
|
@@ -75747,8 +75788,8 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75747
75788
|
const deltaY = pos.endY - pos.startY;
|
|
75748
75789
|
// Calculate bend point (70% along the path with 10° offset for 100° angle)
|
|
75749
75790
|
const bendRatio = 0.7; // How far along to place the bend
|
|
75750
|
-
const midX = pos.startX +
|
|
75751
|
-
const midY = pos.startY +
|
|
75791
|
+
const midX = pos.startX + deltaX * bendRatio;
|
|
75792
|
+
const midY = pos.startY + deltaY * bendRatio + deltaX * 0.1; // 10° offset for 100° angle
|
|
75752
75793
|
const pathData = `M ${pos.startX} ${pos.startY} L ${midX} ${midY} L ${pos.endX} ${pos.endY}`;
|
|
75753
75794
|
pathElement = (jsxRuntimeExports.jsx("path", { d: pathData, stroke: lineColor, strokeWidth: lineThickness, fill: 'none', markerStart: markerStart, markerEnd: markerEnd, opacity: '0.9', strokeLinecap: 'round', strokeLinejoin: 'round' }));
|
|
75754
75795
|
}
|
|
@@ -75790,7 +75831,7 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75790
75831
|
// Check if this annotation should be visible
|
|
75791
75832
|
const isVisible = visibleAnnotationIds.includes(annotation.id);
|
|
75792
75833
|
const ContainerClasses = `
|
|
75793
|
-
${annotation.type === 'label' ? 'transform -translate-x-1/2 -translate-y-
|
|
75834
|
+
${annotation.type === 'label' ? 'transform -translate-x-1/2 -translate-y-1/2' : ''} ${isSelected ? 'ring-1 ring-blue-400' : isDragging === annotation.id ? 'opacity-70 ring-1 ring-red-400' : ''} ${!isVisible ? 'invisible' : ''}
|
|
75794
75835
|
`;
|
|
75795
75836
|
const TextAreaClasses = `
|
|
75796
75837
|
absolute top-1/2 -translate-y-1/2 ${fontFamilyClass} text-${annotation.align}
|
|
@@ -75833,17 +75874,17 @@ function AssemblyAnnotationOverlay({ annotations, setAnnotations, currentAnnotat
|
|
|
75833
75874
|
return (jsxRuntimeExports.jsxs("div", { id: `assembly-annotation-${annotation.id}`, className: cn('w-max relative text-xs pointer-events-auto cursor-pointer flex items-center transition-all', ContainerClasses), onDoubleClick: handleDoubleClick, onMouseDown: handleSelect, children: [jsxRuntimeExports.jsx("div", { style: { height: scale, width: scale }, children: jsxRuntimeExports.jsx(ShapeSVG, { annotation: annotation }) }), jsxRuntimeExports.jsx(Textarea, { rows: 1, value: canContainText ? annotation.text.value : '', placeholder: canContainText ? 'Add Text' : '', readOnly: !canContainText || editingAnnotation !== annotation.id, className: cn(`absolute resize-none bg-transparent cursor-pointer leading-tight w-full !border-none !outline-none !ring-0 z-[2]`, TextAreaClasses), style: {
|
|
75834
75875
|
color: textColor,
|
|
75835
75876
|
fontSize: `${textSize}px`,
|
|
75836
|
-
minHeight: `${textSize}px
|
|
75877
|
+
minHeight: `${textSize}px`,
|
|
75837
75878
|
}, autoFocus: editingAnnotation === annotation.id && canContainText, onChange: (e) => {
|
|
75838
75879
|
// Update the annotation text immediately on change
|
|
75839
75880
|
if (editingAnnotation === annotation.id) {
|
|
75840
75881
|
// Find the current annotation with all its properties
|
|
75841
|
-
const currentAnn = annotations.find(a => a.id === annotation.id);
|
|
75882
|
+
const currentAnn = annotations.find((a) => a.id === annotation.id);
|
|
75842
75883
|
if (!currentAnn)
|
|
75843
75884
|
return;
|
|
75844
75885
|
const updatedAnnotation = Object.assign(Object.assign({}, currentAnn), { text: Object.assign(Object.assign({}, currentAnn.text), { value: e.target.value }) });
|
|
75845
75886
|
// Update annotations array
|
|
75846
|
-
setAnnotations((prev) => prev.map((a) => a.id === annotation.id ? updatedAnnotation : a));
|
|
75887
|
+
setAnnotations((prev) => prev.map((a) => (a.id === annotation.id ? updatedAnnotation : a)));
|
|
75847
75888
|
// Also update currentAnnotation if this is the currently selected annotation
|
|
75848
75889
|
if ((currentAnnotation === null || currentAnnotation === void 0 ? void 0 : currentAnnotation.id) === annotation.id) {
|
|
75849
75890
|
setCurrentAnnotation(updatedAnnotation);
|
|
@@ -75956,11 +75997,41 @@ const Tag = ({ text, className = '' }) => {
|
|
|
75956
75997
|
const backgroundColor = getColor(text);
|
|
75957
75998
|
return (jsxRuntimeExports.jsx("span", { className: `px-3 py-1.5 rounded-md text-sm font-medium text-white ${className}`, style: { backgroundColor }, children: text }));
|
|
75958
75999
|
};
|
|
75959
|
-
const AssemblyViewMode = ({ phases, htmlContent, className = '', productTitle, parts, organizationId, productId, editMode = false, onUploadImage, onPhasesUpdate, }) => {
|
|
76000
|
+
const AssemblyViewMode = ({ phases, htmlContent, className = '', productTitle, parts, organizationId, productId, editMode = false, onUploadImage, onPhasesUpdate, routePhaseId, routeStepId, onAssemblyChange, }) => {
|
|
75960
76001
|
var _a;
|
|
75961
|
-
|
|
75962
|
-
const
|
|
75963
|
-
|
|
76002
|
+
// Initialize state based on route props
|
|
76003
|
+
const getInitialPhaseIndex = () => {
|
|
76004
|
+
if (routePhaseId) {
|
|
76005
|
+
const index = phases.findIndex(p => p.id === routePhaseId);
|
|
76006
|
+
return index >= 0 ? index : 0;
|
|
76007
|
+
}
|
|
76008
|
+
return 0;
|
|
76009
|
+
};
|
|
76010
|
+
const getInitialStepIndex = () => {
|
|
76011
|
+
if (routePhaseId && routeStepId) {
|
|
76012
|
+
const phaseIndex = phases.findIndex(p => p.id === routePhaseId);
|
|
76013
|
+
if (phaseIndex >= 0) {
|
|
76014
|
+
const stepIndex = phases[phaseIndex].steps.findIndex(s => s.id === routeStepId);
|
|
76015
|
+
return stepIndex >= 0 ? stepIndex : 0;
|
|
76016
|
+
}
|
|
76017
|
+
}
|
|
76018
|
+
return 0;
|
|
76019
|
+
};
|
|
76020
|
+
const getInitialView = () => {
|
|
76021
|
+
if (routePhaseId && routeStepId) {
|
|
76022
|
+
const phaseIndex = phases.findIndex(p => p.id === routePhaseId);
|
|
76023
|
+
if (phaseIndex >= 0) {
|
|
76024
|
+
const stepIndex = phases[phaseIndex].steps.findIndex(s => s.id === routeStepId);
|
|
76025
|
+
if (stepIndex >= 0) {
|
|
76026
|
+
return 'step';
|
|
76027
|
+
}
|
|
76028
|
+
}
|
|
76029
|
+
}
|
|
76030
|
+
return 'overview';
|
|
76031
|
+
};
|
|
76032
|
+
const [currentPhaseIndex, setCurrentPhaseIndex] = React.useState(getInitialPhaseIndex);
|
|
76033
|
+
const [currentStepIndex, setCurrentStepIndex] = React.useState(getInitialStepIndex);
|
|
76034
|
+
const [currentView, setCurrentView] = React.useState(getInitialView);
|
|
75964
76035
|
const [isAnimating, setIsAnimating] = React.useState(false);
|
|
75965
76036
|
const [isPreparingAnimation, setIsPreparingAnimation] = React.useState(false);
|
|
75966
76037
|
const containerRef = React__namespace.default.useRef(null);
|
|
@@ -76301,16 +76372,40 @@ const AssemblyViewMode = ({ phases, htmlContent, className = '', productTitle, p
|
|
|
76301
76372
|
// Trigger debounced save for step description
|
|
76302
76373
|
debouncedSave(stepId, content, 'step-description');
|
|
76303
76374
|
}, [debouncedSave]);
|
|
76304
|
-
// Load annotations when step changes - same logic as Editor3D
|
|
76305
|
-
|
|
76375
|
+
// Load annotations when step changes - same logic as Editor3D with migration
|
|
76376
|
+
React.useEffect(() => {
|
|
76306
76377
|
// Only update if the step ID actually changed
|
|
76307
76378
|
if (prevStepIdRef.current !== (currentStep === null || currentStep === void 0 ? void 0 : currentStep.id)) {
|
|
76308
76379
|
prevStepIdRef.current = (currentStep === null || currentStep === void 0 ? void 0 : currentStep.id) || null;
|
|
76309
|
-
|
|
76310
|
-
|
|
76380
|
+
if (currentStep === null || currentStep === void 0 ? void 0 : currentStep.annotations) {
|
|
76381
|
+
// MIGRATION LOGIC: Convert old pulse format to new format
|
|
76382
|
+
// Background: In commit 8e30c8a, pulse structure was changed from:
|
|
76383
|
+
// arrow.endPulse (boolean) and arrow.pulseColor (ColorLabel)
|
|
76384
|
+
// to:
|
|
76385
|
+
// pulse: { show: boolean, color: ColorLabel }
|
|
76386
|
+
// This migration ensures existing annotations don't lose their pulse settings
|
|
76387
|
+
const migratedAnnotations = currentStep.annotations.map((annotation) => {
|
|
76388
|
+
var _a;
|
|
76389
|
+
// Check if annotation has old pulse format but no new pulse property
|
|
76390
|
+
if (((_a = annotation.arrow) === null || _a === void 0 ? void 0 : _a.endPulse) && !annotation.pulse) {
|
|
76391
|
+
return Object.assign(Object.assign({}, annotation), { pulse: {
|
|
76392
|
+
show: annotation.arrow.endPulse,
|
|
76393
|
+
color: annotation.arrow.pulseColor || 'pulse orange'
|
|
76394
|
+
},
|
|
76395
|
+
// Clean up old properties from arrow object
|
|
76396
|
+
arrow: Object.assign(Object.assign({}, annotation.arrow), { endPulse: undefined, pulseColor: undefined }) });
|
|
76397
|
+
}
|
|
76398
|
+
// Return annotation as-is if already migrated or doesn't need migration
|
|
76399
|
+
return annotation;
|
|
76400
|
+
});
|
|
76401
|
+
setAssemblyAnnotations(migratedAnnotations);
|
|
76402
|
+
console.log('📝 View mode annotations loaded and migrated for step:', currentStep === null || currentStep === void 0 ? void 0 : currentStep.id, 'count:', migratedAnnotations.length);
|
|
76403
|
+
}
|
|
76404
|
+
else {
|
|
76405
|
+
setAssemblyAnnotations([]);
|
|
76406
|
+
}
|
|
76311
76407
|
// Reset visible annotations (default to all hidden in view mode)
|
|
76312
76408
|
setVisibleAnnotationIds([]);
|
|
76313
|
-
console.log('📝 View mode annotations loaded for step:', currentStep === null || currentStep === void 0 ? void 0 : currentStep.id, 'count:', stepAnnotations.length);
|
|
76314
76409
|
}
|
|
76315
76410
|
}, [currentStep === null || currentStep === void 0 ? void 0 : currentStep.id, currentStep]);
|
|
76316
76411
|
// Navigation functions
|
|
@@ -76327,33 +76422,115 @@ const AssemblyViewMode = ({ phases, htmlContent, className = '', productTitle, p
|
|
|
76327
76422
|
}
|
|
76328
76423
|
return false;
|
|
76329
76424
|
}, [currentPhase, currentStepIndex, currentPhaseIndex, phases]);
|
|
76425
|
+
const canGoPrevious = React.useMemo(() => {
|
|
76426
|
+
if (!currentPhase)
|
|
76427
|
+
return false;
|
|
76428
|
+
// If not at first step of current phase, can go previous
|
|
76429
|
+
if (currentStepIndex > 0)
|
|
76430
|
+
return true;
|
|
76431
|
+
// If at first step of current phase, check if there's a previous phase with steps
|
|
76432
|
+
if (currentPhaseIndex > 0) {
|
|
76433
|
+
const previousPhase = phases[currentPhaseIndex - 1];
|
|
76434
|
+
return previousPhase.steps.length > 0;
|
|
76435
|
+
}
|
|
76436
|
+
return false;
|
|
76437
|
+
}, [currentPhase, currentStepIndex, currentPhaseIndex, phases]);
|
|
76330
76438
|
const handleNext = () => {
|
|
76439
|
+
var _a, _b, _c;
|
|
76331
76440
|
if (!currentPhase)
|
|
76332
76441
|
return;
|
|
76442
|
+
let newPhaseIndex = currentPhaseIndex;
|
|
76443
|
+
let newStepIndex = currentStepIndex;
|
|
76333
76444
|
if (currentStepIndex < currentPhase.steps.length - 1) {
|
|
76334
|
-
|
|
76445
|
+
newStepIndex = currentStepIndex + 1;
|
|
76446
|
+
setCurrentStepIndex(newStepIndex);
|
|
76335
76447
|
}
|
|
76336
76448
|
else if (currentPhaseIndex < phases.length - 1) {
|
|
76337
76449
|
const nextPhaseIndex = currentPhaseIndex + 1;
|
|
76338
76450
|
const nextPhase = phases[nextPhaseIndex];
|
|
76339
76451
|
if (nextPhase.steps.length > 0) {
|
|
76340
|
-
|
|
76341
|
-
|
|
76452
|
+
newPhaseIndex = nextPhaseIndex;
|
|
76453
|
+
newStepIndex = 0;
|
|
76454
|
+
setCurrentPhaseIndex(newPhaseIndex);
|
|
76455
|
+
setCurrentStepIndex(newStepIndex);
|
|
76456
|
+
}
|
|
76457
|
+
}
|
|
76458
|
+
// Call onAssemblyChange if provided
|
|
76459
|
+
if (onAssemblyChange) {
|
|
76460
|
+
const phaseId = (_a = phases[newPhaseIndex]) === null || _a === void 0 ? void 0 : _a.id;
|
|
76461
|
+
const stepId = currentView === 'step' ? (_c = (_b = phases[newPhaseIndex]) === null || _b === void 0 ? void 0 : _b.steps[newStepIndex]) === null || _c === void 0 ? void 0 : _c.id : undefined;
|
|
76462
|
+
if (phaseId) {
|
|
76463
|
+
onAssemblyChange(phaseId, stepId);
|
|
76464
|
+
}
|
|
76465
|
+
}
|
|
76466
|
+
};
|
|
76467
|
+
const handlePrevious = () => {
|
|
76468
|
+
var _a, _b, _c;
|
|
76469
|
+
if (!currentPhase)
|
|
76470
|
+
return;
|
|
76471
|
+
let newPhaseIndex = currentPhaseIndex;
|
|
76472
|
+
let newStepIndex = currentStepIndex;
|
|
76473
|
+
if (currentStepIndex > 0) {
|
|
76474
|
+
newStepIndex = currentStepIndex - 1;
|
|
76475
|
+
setCurrentStepIndex(newStepIndex);
|
|
76476
|
+
}
|
|
76477
|
+
else if (currentPhaseIndex > 0) {
|
|
76478
|
+
const previousPhaseIndex = currentPhaseIndex - 1;
|
|
76479
|
+
const previousPhase = phases[previousPhaseIndex];
|
|
76480
|
+
if (previousPhase.steps.length > 0) {
|
|
76481
|
+
newPhaseIndex = previousPhaseIndex;
|
|
76482
|
+
newStepIndex = previousPhase.steps.length - 1;
|
|
76483
|
+
setCurrentPhaseIndex(newPhaseIndex);
|
|
76484
|
+
setCurrentStepIndex(newStepIndex);
|
|
76485
|
+
}
|
|
76486
|
+
}
|
|
76487
|
+
// Call onAssemblyChange if provided
|
|
76488
|
+
if (onAssemblyChange) {
|
|
76489
|
+
const phaseId = (_a = phases[newPhaseIndex]) === null || _a === void 0 ? void 0 : _a.id;
|
|
76490
|
+
const stepId = currentView === 'step' ? (_c = (_b = phases[newPhaseIndex]) === null || _b === void 0 ? void 0 : _b.steps[newStepIndex]) === null || _c === void 0 ? void 0 : _c.id : undefined;
|
|
76491
|
+
if (phaseId) {
|
|
76492
|
+
onAssemblyChange(phaseId, stepId);
|
|
76342
76493
|
}
|
|
76343
76494
|
}
|
|
76344
76495
|
};
|
|
76345
76496
|
const handlePhaseChange = (phaseIndex) => {
|
|
76497
|
+
var _a;
|
|
76346
76498
|
setCurrentPhaseIndex(phaseIndex);
|
|
76347
76499
|
setCurrentStepIndex(0);
|
|
76348
76500
|
setCurrentView('overview');
|
|
76501
|
+
// Call onAssemblyChange if provided
|
|
76502
|
+
if (onAssemblyChange) {
|
|
76503
|
+
const phaseId = (_a = phases[phaseIndex]) === null || _a === void 0 ? void 0 : _a.id;
|
|
76504
|
+
if (phaseId) {
|
|
76505
|
+
onAssemblyChange(phaseId, undefined); // No stepId in overview mode
|
|
76506
|
+
}
|
|
76507
|
+
}
|
|
76349
76508
|
};
|
|
76350
76509
|
const handleStepClick = (stepIndex) => {
|
|
76510
|
+
var _a;
|
|
76351
76511
|
setCurrentStepIndex(stepIndex);
|
|
76352
76512
|
setCurrentView('step');
|
|
76513
|
+
// Call onAssemblyChange if provided
|
|
76514
|
+
if (onAssemblyChange) {
|
|
76515
|
+
const phaseId = currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.id;
|
|
76516
|
+
const stepId = (_a = currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.steps[stepIndex]) === null || _a === void 0 ? void 0 : _a.id;
|
|
76517
|
+
if (phaseId) {
|
|
76518
|
+
onAssemblyChange(phaseId, stepId);
|
|
76519
|
+
}
|
|
76520
|
+
}
|
|
76353
76521
|
};
|
|
76354
76522
|
const handleBeginPhase = () => {
|
|
76523
|
+
var _a;
|
|
76355
76524
|
setCurrentStepIndex(0);
|
|
76356
76525
|
setCurrentView('step');
|
|
76526
|
+
// Call onAssemblyChange if provided
|
|
76527
|
+
if (onAssemblyChange) {
|
|
76528
|
+
const phaseId = currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.id;
|
|
76529
|
+
const stepId = (_a = currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.steps[0]) === null || _a === void 0 ? void 0 : _a.id;
|
|
76530
|
+
if (phaseId) {
|
|
76531
|
+
onAssemblyChange(phaseId, stepId);
|
|
76532
|
+
}
|
|
76533
|
+
}
|
|
76357
76534
|
};
|
|
76358
76535
|
const handleToggleAnnotation = (annotationId) => {
|
|
76359
76536
|
// Note: Camera settings functionality would require additional props if needed
|
|
@@ -76427,7 +76604,7 @@ const AssemblyViewMode = ({ phases, htmlContent, className = '', productTitle, p
|
|
|
76427
76604
|
if (phases.length === 0) {
|
|
76428
76605
|
return (jsxRuntimeExports.jsx("div", { className: `flex items-center justify-center h-full ${className}`, children: jsxRuntimeExports.jsxs("div", { className: 'text-center text-white/60 space-y-2', children: [jsxRuntimeExports.jsx("p", { className: 'text-lg', children: "No assembly phases available" }), jsxRuntimeExports.jsx("p", { className: 'text-sm', children: "Import assembly instructions to get started" })] }) }));
|
|
76429
76606
|
}
|
|
76430
|
-
return (jsxRuntimeExports.jsx("div", { className: `
|
|
76607
|
+
return (jsxRuntimeExports.jsx("div", { className: `h-full max-h-screen w-full relative bg-[#161617] rounded-3xl ${className}`, children: jsxRuntimeExports.jsxs("div", { className: 'grid grid-cols-1 lg:grid-cols-5 gap-4 px-4 py-4 h-full', children: [jsxRuntimeExports.jsxs("div", { className: 'lg:col-span-3 flex flex-col w-full h-full relative bg-transparent border rounded-3xl border-[#313133] min-h-0', children: [jsxRuntimeExports.jsxs("div", { className: 'rounded-lg py-6 px-18 flex-shrink-0 h-[120px] flex flex-col justify-end', children: [jsxRuntimeExports.jsxs("div", { className: 'flex items-center justify-between mb-4', children: [jsxRuntimeExports.jsxs("div", { className: 'text-sm text-white/70', children: [productTitle, " Assembly"] }), jsxRuntimeExports.jsxs("div", { className: 'text-sm text-white/70', children: [completedStepsInCurrentPhase, "/", totalStepsInCurrentPhase, " Complete"] })] }), jsxRuntimeExports.jsx("div", { className: 'flex space-x-1', children: currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.steps.map((_, index) => (jsxRuntimeExports.jsx("div", { className: `h-1 rounded-sm flex-1 transition-all duration-300 ${index < completedStepsInCurrentPhase ? 'bg-white' : 'bg-[#313133]'}` }, index))) })] }), jsxRuntimeExports.jsxs("div", { ref: containerRef, className: 'w-full relative flex-1 min-h-[400px]', style: { backgroundColor: 'transparent' }, children: [currentView === 'step' && assemblyAnnotations.length > 0 && (jsxRuntimeExports.jsx("div", { className: 'absolute right-[4.5rem] z-20', children: jsxRuntimeExports.jsxs(DropdownMenu, { children: [jsxRuntimeExports.jsx(DropdownMenuTrigger, { asChild: true, children: jsxRuntimeExports.jsxs(Button, { variant: 'outline', size: 'sm', className: 'flex items-center gap-2 px-3 py-1.5', children: [jsxRuntimeExports.jsxs("div", { className: 'relative', children: [jsxRuntimeExports.jsx(CiBellOn, { className: 'size-5 stroke-[0.7] text-[#AA423A]' }), jsxRuntimeExports.jsx("p", { className: 'absolute top-0 right-0 rounded-full text-[7px] bg-[#AA423A] text-white size-2.5 text-center', children: assemblyAnnotations.length })] }), "Annotations", jsxRuntimeExports.jsx(react$2.Icon, { icon: 'ph:caret-down', className: 'w-3 h-3 ml-1' })] }) }), jsxRuntimeExports.jsxs(DropdownMenuContent, { align: 'end', className: 'bg-[#232326] border-gray-700 min-w-[200px]', children: [jsxRuntimeExports.jsx(DropdownMenuLabel, { className: 'text-gray-400 text-xs', children: "Annotation Controls" }), jsxRuntimeExports.jsx(DropdownMenuSeparator, { className: 'bg-gray-700' }), jsxRuntimeExports.jsxs(DropdownMenuItem, { onClick: () => setVisibleAnnotationIds(assemblyAnnotations.map((a) => a.id)), className: 'text-white hover:bg-gray-800 cursor-pointer', children: [jsxRuntimeExports.jsx(react$2.Icon, { icon: 'ph:eye', className: 'w-4 h-4 mr-2' }), "Show All Annotations"] }), jsxRuntimeExports.jsxs(DropdownMenuItem, { onClick: () => setVisibleAnnotationIds([]), className: 'text-white hover:bg-gray-800 cursor-pointer', children: [jsxRuntimeExports.jsx(react$2.Icon, { icon: 'ph:eye-slash', className: 'w-4 h-4 mr-2' }), "Hide All Annotations"] }), jsxRuntimeExports.jsx(DropdownMenuSeparator, { className: 'bg-gray-700' }), jsxRuntimeExports.jsx(DropdownMenuLabel, { className: 'text-gray-400 text-xs', children: "Individual Annotations" }), assemblyAnnotations.map((annotation, index) => {
|
|
76431
76608
|
const displayText = annotation.text.value || `${annotation.type === 'arrow' ? 'Arrow' : 'Label'} ${index + 1}`;
|
|
76432
76609
|
const truncatedText = displayText.length > 30 ? displayText.substring(0, 30) + '...' : displayText;
|
|
76433
76610
|
const isVisible = visibleAnnotationIds.includes(annotation.id);
|
|
@@ -76442,9 +76619,13 @@ const AssemblyViewMode = ({ phases, htmlContent, className = '', productTitle, p
|
|
|
76442
76619
|
setCurrentPhaseIndex(targetPhaseIndex);
|
|
76443
76620
|
setCurrentStepIndex(targetStepIndex);
|
|
76444
76621
|
setCurrentView('step');
|
|
76622
|
+
// Call onAssemblyChange when navigation happens from 3D viewer
|
|
76623
|
+
if (onAssemblyChange) {
|
|
76624
|
+
onAssemblyChange(phaseId, stepId);
|
|
76625
|
+
}
|
|
76445
76626
|
}
|
|
76446
76627
|
}
|
|
76447
|
-
}, isAnimating: isAnimating, isPreparingAnimation: isPreparingAnimation, setIsAnimating: setIsAnimating, setIsPreparingAnimation: setIsPreparingAnimation, onElementsReady: handleElementsReady })) : (jsxRuntimeExports.jsx("div", { className: 'flex items-center justify-center h-full text-gray-500', children: jsxRuntimeExports.jsx("p", { children: "3D Model Loading..." }) })), htmlContent && currentView === 'step' && assemblyAnnotations.length > 0 && (jsxRuntimeExports.jsx(AssemblyAnnotationOverlay, { annotations: assemblyAnnotations, setAnnotations: () => { }, currentAnnotation: null, setCurrentAnnotation: () => { }, isPlacingAnnotation: false, setIsPlacingAnnotation: () => { }, runtimeRef: runtimeRef, isPenToolActive: false, visibleAnnotationIds: visibleAnnotationIds, setVisibleAnnotationIds: setVisibleAnnotationIds, setCameraSettings: () => { }, onActivatePenTool: () => { }, onCloseTypeSelector: () => { } }))] })] })] }), jsxRuntimeExports.jsxs("div", { className: 'lg:col-span-2 bg-[#0D0D0D] rounded-3xl w-full px-6 pt-4 pb-6 flex flex-col min-h-
|
|
76628
|
+
}, isAnimating: isAnimating, isPreparingAnimation: isPreparingAnimation, setIsAnimating: setIsAnimating, setIsPreparingAnimation: setIsPreparingAnimation, onElementsReady: handleElementsReady, handleNext: handleNext, handlePrevious: handlePrevious })) : (jsxRuntimeExports.jsx("div", { className: 'flex items-center justify-center h-full text-gray-500', children: jsxRuntimeExports.jsx("p", { children: "3D Model Loading..." }) })), htmlContent && currentView === 'step' && assemblyAnnotations.length > 0 && (jsxRuntimeExports.jsx(AssemblyAnnotationOverlay, { annotations: assemblyAnnotations, setAnnotations: () => { }, currentAnnotation: null, setCurrentAnnotation: () => { }, isPlacingAnnotation: false, setIsPlacingAnnotation: () => { }, runtimeRef: runtimeRef, isPenToolActive: false, visibleAnnotationIds: visibleAnnotationIds, setVisibleAnnotationIds: setVisibleAnnotationIds, setCameraSettings: () => { }, onActivatePenTool: () => { }, onCloseTypeSelector: () => { } }))] })] })] }), jsxRuntimeExports.jsxs("div", { className: 'lg:col-span-2 bg-[#0D0D0D] rounded-3xl w-full h-full px-6 pt-4 pb-6 flex flex-col min-h-0', children: [jsxRuntimeExports.jsx("div", { className: 'mb-4 max-w-[12rem]', children: jsxRuntimeExports.jsx(TnkrSelect, { value: { value: currentPhaseIndex.toString(), label: ((_a = phases[currentPhaseIndex]) === null || _a === void 0 ? void 0 : _a.title) || '' }, options: phases.map((phase, index) => ({ value: index.toString(), label: phase.title })), onChange: (option) => handlePhaseChange(Number(option.value)) }) }), jsxRuntimeExports.jsx("div", { className: 'border-b border-[#313133] mb-6' }), jsxRuntimeExports.jsx("div", { className: 'flex-1 flex flex-col overflow-y-auto min-h-0', children: currentView === 'overview' ? (
|
|
76448
76629
|
// Phase Overview
|
|
76449
76630
|
// Check if phase has "Add a title" and no content
|
|
76450
76631
|
(currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.title) === 'Add a title' &&
|
|
@@ -76475,11 +76656,13 @@ const AssemblyViewMode = ({ phases, htmlContent, className = '', productTitle, p
|
|
|
76475
76656
|
}, onUploadImage: onUploadImage, customExtensionSet: getBasicExtensions(), className: "text-white/70 leading-relaxed", minHeight: 20, readOnly: !editMode }, `step-description-${currentStep === null || currentStep === void 0 ? void 0 : currentStep.id}`) }), jsxRuntimeExports.jsxs("div", { className: 'space-y-6 flex-1', children: [jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx("h3", { className: 'text-lg font-semibold mb-4 text-white', children: "Parts Needed" }), (currentStep === null || currentStep === void 0 ? void 0 : currentStep.parts) && currentStep.parts.length > 0 ? (jsxRuntimeExports.jsx("div", { className: 'flex flex-wrap gap-2', children: currentStep.parts.map((part, index) => {
|
|
76476
76657
|
const displayName = part.name;
|
|
76477
76658
|
return jsxRuntimeExports.jsx(Tag, { text: displayName }, part.id || index);
|
|
76478
|
-
}) })) : (jsxRuntimeExports.jsx("p", { className: 'text-white/50 text-sm', children: "No parts required for this step" }))] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx("h3", { className: 'text-lg font-semibold mb-4 text-white', children: "Tools" }), (currentStep === null || currentStep === void 0 ? void 0 : currentStep.tools) && currentStep.tools.length > 0 ? (jsxRuntimeExports.jsx("div", { className: 'flex flex-wrap gap-2', children: currentStep.tools.map((tool, index) => (jsxRuntimeExports.jsx(Tag, { text: tool.title }, tool.id || index))) })) : (jsxRuntimeExports.jsx("p", { className: 'text-white/50 text-sm', children: "No tools required for this step" }))] })] }), jsxRuntimeExports.
|
|
76479
|
-
|
|
76480
|
-
|
|
76481
|
-
|
|
76482
|
-
|
|
76659
|
+
}) })) : (jsxRuntimeExports.jsx("p", { className: 'text-white/50 text-sm', children: "No parts required for this step" }))] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx("h3", { className: 'text-lg font-semibold mb-4 text-white', children: "Tools" }), (currentStep === null || currentStep === void 0 ? void 0 : currentStep.tools) && currentStep.tools.length > 0 ? (jsxRuntimeExports.jsx("div", { className: 'flex flex-wrap gap-2', children: currentStep.tools.map((tool, index) => (jsxRuntimeExports.jsx(Tag, { text: tool.title }, tool.id || index))) })) : (jsxRuntimeExports.jsx("p", { className: 'text-white/50 text-sm', children: "No tools required for this step" }))] })] }), jsxRuntimeExports.jsxs("div", { className: 'flex items-center justify-between gap-4', children: [canGoPrevious && (jsxRuntimeExports.jsx(Button, { onClick: handlePrevious, className: 'bg-transparent border border-[#313133] hover:bg-[#232326] text-white/70 hover:text-white px-6 py-2.5 rounded-lg font-medium h-11', children: currentStepIndex === 0 && currentPhaseIndex > 0
|
|
76660
|
+
? 'Previous Phase'
|
|
76661
|
+
: 'Previous Step' })), jsxRuntimeExports.jsx(Button, { onClick: handleNext, disabled: !canGoNext, className: 'bg-[#AA423A] hover:bg-[#8A322E] disabled:opacity-50 disabled:cursor-not-allowed text-white px-6 py-2.5 rounded-lg font-medium h-11 ml-auto', children: currentStepIndex === (currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.steps.length) - 1
|
|
76662
|
+
? currentPhaseIndex < phases.length - 1
|
|
76663
|
+
? 'Next Phase'
|
|
76664
|
+
: 'Complete'
|
|
76665
|
+
: 'Next Step' })] })] })) })] })] }) }));
|
|
76483
76666
|
};
|
|
76484
76667
|
|
|
76485
76668
|
/**
|