Refactor compare components and version management

- Updated SVG attributes in SimulationIcons to use camelCase for color interpolation filters.
- Refactored import paths for ComparePopUp and CompareLayOut to new directory structure.
- Enhanced VersionHistory component to utilize version store for better state management.
- Removed deprecated CompareLayOut and compare components, replacing them with new versions.
- Implemented VersionSaved component to display notifications for newly saved versions.
- Added functionality to save and edit version names and descriptions.
- Updated styles for version notifications and editing popups.
- Improved AddButtons component to dynamically set IDs based on side.
- Enhanced Project component to integrate new version management features.
This commit is contained in:
Nalvazhuthi
2025-05-16 18:02:46 +05:30
parent d6dceb400f
commit 933f87a8cb
12 changed files with 707 additions and 86 deletions

View File

@@ -0,0 +1,77 @@
import React from "react";
import { InfoIcon } from "../../icons/ShortcutIcons";
import { SaveDiskIcon } from "../../icons/ExportCommonIcons";
import { useCompareStore } from "../../../store/builder/store";
import OuterClick from "../../../utils/outerClick";
interface ComparePopUpProps {
onClose: () => void;
}
const ComparePopUp: React.FC<ComparePopUpProps> = ({ onClose }) => {
const { setComparePopUp } = useCompareStore();
OuterClick({
contextClassName: ["compare-wrapper", "input"],
setMenuVisible: () => setComparePopUp(false),
});
return (
<div className="compare-container">
<div className="compare-wrapper">
<div className="grid-wrapper">
<div className="header">
Do you want to save this version before comparing?
</div>
<div className="cards-container">
<div className="card"></div>
<div className="card"></div>
<div className="card-layout-wrapper">
<div className="card-layout-container">
<div className="tab-header">
<div className="label-tab">Layout !</div>
<div className="status"></div>
</div>
<div className="icon">
<SaveDiskIcon />
</div>
<div className="skeleton-wrapper">
<div className="skeleton"></div>
<div className="skeleton"></div>
<div className="skeleton"></div>
</div>
</div>
</div>
<div className="card"></div>
<div className="card"></div>
</div>
<div className="button-wrapper">
<div className="button-group">
<button className="save btn" onClick={onClose}>
Save & Continue
</button>
<div className="replace btn">Replace Existing Version</div>
</div>
<button
className="cancel btn"
id="compare-cancel-btn"
onClick={() => setComparePopUp(false)}
>
Cancel
</button>
</div>
</div>
<div className="footer">
<InfoIcon /> Save this version and proceed.
</div>
</div>
</div>
);
};
export default ComparePopUp;

View File

@@ -0,0 +1,179 @@
import React, { useState, useRef, useEffect } from "react";
import {
CompareLayoutIcon,
LayoutIcon,
ResizerIcon,
} from "../../icons/SimulationIcons";
import { useSaveVersion } from "../../../store/builder/store";
import Search from "../inputs/Search";
import OuterClick from "../../../utils/outerClick";
import RegularDropDown from "../inputs/RegularDropDown";
interface Layout {
id: number;
name: string;
}
interface CompareLayoutProps {
dummyLayouts: Layout[];
}
const CompareLayOut: React.FC<CompareLayoutProps> = ({ dummyLayouts }) => {
const [width, setWidth] = useState("50vw");
const [isResizing, setIsResizing] = useState(false);
const [showLayoutDropdown, setShowLayoutDropdown] = useState(false);
const [selectedLayout, setSelectedLayout] = useState<string | null>(null); // Track selected layout
const wrapperRef = useRef<HTMLDivElement>(null);
const startWidthRef = useRef<number>(0);
const startXRef = useRef<number>(0);
const { setIsVersionSaved } = useSaveVersion();
OuterClick({
contextClassName: ["displayLayouts-container", "selectLayout"],
setMenuVisible: () => setShowLayoutDropdown(false),
});
const handleStartResizing = (e: React.MouseEvent) => {
e.preventDefault();
setIsResizing(true);
startXRef.current = e.clientX;
if (wrapperRef.current) {
startWidthRef.current = wrapperRef.current.getBoundingClientRect().width;
}
};
const handleMouseMove = (e: MouseEvent) => {
if (!isResizing || !wrapperRef.current) return;
const dx = startXRef.current - e.clientX;
const newWidthPx = startWidthRef.current + dx;
const viewportWidth = window.innerWidth;
const newWidthVw = (newWidthPx / viewportWidth) * 100;
if (newWidthVw <= 10) {
setWidth("0px");
} else if (newWidthVw <= 90) {
setWidth(`${newWidthPx}px`);
}
};
const handleMouseUp = () => {
if (!isResizing) return;
if (wrapperRef.current) {
const finalWidthPx = wrapperRef.current.getBoundingClientRect().width;
const viewportWidth = window.innerWidth;
const finalWidthVw = (finalWidthPx / viewportWidth) * 100;
if (finalWidthVw <= 10) {
setWidth("0px");
setIsVersionSaved(false);
} else {
setWidth(`${finalWidthVw}vw`);
}
}
setIsResizing(false);
};
useEffect(() => {
if (isResizing) {
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
document.body.classList.add("resizing-active");
}
return () => {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
document.body.classList.remove("resizing-active");
};
}, [isResizing]);
// Maintain proportional width on window resize
useEffect(() => {
const handleResize = () => {
if (!wrapperRef.current || isResizing) return;
const currentWidth = wrapperRef.current.style.width;
if (currentWidth === "0px" || currentWidth.endsWith("vw")) return;
const pxWidth = parseFloat(currentWidth);
const vwWidth = (pxWidth / window.innerWidth) * 100;
setWidth(`${vwWidth}vw`);
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, [isResizing]);
const handleSelectLayout = (option: string) => {
setSelectedLayout(option); // Set selected layout
console.log("Selected layout:", option);
};
return (
<div
className={`compareLayOut-wrapper ${width === "0px" ? "closed" : ""}`}
ref={wrapperRef}
style={{ width }}
>
<div className="chooseLayout-container">
<div className="resizer" onMouseDown={handleStartResizing}>
<ResizerIcon />
</div>
{width !== "0px" &&
!selectedLayout && ( // Show only if no layout selected
<div className="chooseLayout-wrapper">
<div className="icon">
<CompareLayoutIcon />
</div>
<div className="value">Choose Layout to compare</div>
<button
className="selectLayout"
onClick={() => setShowLayoutDropdown(!showLayoutDropdown)}
>
Select Layout
</button>
{showLayoutDropdown && (
<div className="displayLayouts-container">
<div className="header">Layouts</div>
<Search onChange={() => {}} />
<div className="layouts-container">
{dummyLayouts.map((layout) => (
<button
key={layout.id}
className="layout-wrapper"
onClick={() => {
handleSelectLayout(layout.name);
setShowLayoutDropdown(false);
}}
>
<LayoutIcon />
<div className="layout">{layout.name}</div>
</button>
))}
</div>
</div>
)}
</div>
)}
{/* Always show after layout is selected */}
{width !== "0px" && selectedLayout && (
<div className="selectLayout-wrapper">
<RegularDropDown
header={selectedLayout}
options={dummyLayouts.map((l) => l.name)} // Pass layout names as options
onSelect={handleSelectLayout}
search={false}
/>
</div>
)}
</div>
</div>
);
};
export default CompareLayOut;