feat: Implement version saving functionality and layout comparison feature
- Added `useSaveVersion` store to manage version saving state. - Updated `SideBarLeft` and `SideBarRight` components to conditionally render based on version saving state. - Introduced `CompareLayOut` component for layout comparison with resizing functionality. - Created `ComparePopUp` component to prompt users to save versions before comparing layouts. - Enhanced `Simulations` component to handle version saving and comparison logic. - Updated `Project` page to integrate layout selection and comparison features. - Added styles for the new comparison layout and pop-up components. - Refactored shortcut handling to include version saving state management.
This commit is contained in:
parent
4daed0f09a
commit
d187e4cc20
|
@ -386,3 +386,452 @@ export function StorageCapacityIcon() {
|
|||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function CompareLayoutIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="182"
|
||||
height="118"
|
||||
viewBox="0 0 182 118"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g filter="url(#filter0_d_3106_8112)">
|
||||
<rect x="24" y="4" width="134" height="106" rx="6" fill="#FCFDFD" />
|
||||
<rect
|
||||
x="24.5"
|
||||
y="4.5"
|
||||
width="133"
|
||||
height="105"
|
||||
rx="5.5"
|
||||
stroke="#E5E5EA"
|
||||
/>
|
||||
</g>
|
||||
<rect x="98" y="12" width="2" height="2" fill="#E5E5EA" />
|
||||
<rect x="98" y="19" width="2" height="2" fill="#E5E5EA" />
|
||||
<rect x="98" y="25" width="2" height="2" fill="#E5E5EA" />
|
||||
<rect x="98" y="33" width="2" height="2" fill="#E5E5EA" />
|
||||
<rect x="98" y="39" width="2" height="2" fill="#E5E5EA" />
|
||||
<rect x="104" y="12" width="7" height="2" fill="#E5E5EA" />
|
||||
<rect x="104" y="19" width="13" height="2" fill="#E5E5EA" />
|
||||
<rect x="111" y="26" width="19" height="2" fill="#E5E5EA" />
|
||||
<rect x="133" y="26" width="10" height="2" fill="#E5E5EA" />
|
||||
<rect x="111" y="32" width="10" height="2" fill="#E5E5EA" />
|
||||
<rect x="116" y="39" width="5" height="2" fill="#E5E5EA" />
|
||||
<rect x="103" y="46" width="9" height="2" fill="#E5E5EA" />
|
||||
<rect x="111" y="53" width="11" height="2" fill="#E5E5EA" />
|
||||
<rect x="104" y="60" width="7" height="2" fill="#E5E5EA" />
|
||||
<rect x="115" y="60" width="11" height="2" fill="#E5E5EA" />
|
||||
<rect x="130" y="60" width="22" height="2" fill="#E5E5EA" />
|
||||
<rect x="124" y="53" width="7" height="2" fill="#E5E5EA" />
|
||||
<rect x="135" y="53" width="17" height="2" fill="#E5E5EA" />
|
||||
<rect x="114" y="46" width="4" height="2" fill="#E5E5EA" />
|
||||
<rect x="121" y="46" width="21" height="2" fill="#E5E5EA" />
|
||||
<rect x="144" y="46" width="4" height="2" fill="#E5E5EA" />
|
||||
<rect x="124" y="39" width="11" height="2" fill="#E5E5EA" />
|
||||
<rect x="143" y="39" width="7" height="2" fill="#E5E5EA" />
|
||||
<rect x="124" y="32" width="10" height="2" fill="#E5E5EA" />
|
||||
<rect x="137" y="32" width="10" height="2" fill="#E5E5EA" />
|
||||
<rect x="151" y="32" width="3" height="2" fill="#E5E5EA" />
|
||||
<rect x="119" y="19" width="5" height="2" fill="#E5E5EA" />
|
||||
<rect x="127" y="19" width="8" height="2" fill="#E5E5EA" />
|
||||
<rect x="113" y="12" width="5" height="2" fill="#E5E5EA" />
|
||||
<rect x="119" y="12" width="20" height="2" fill="#E5E5EA" />
|
||||
<g filter="url(#filter1_f_3106_8112)">
|
||||
<path d="M92 5V109.5" stroke="#B392F0" strokeLinecap="round" />
|
||||
</g>
|
||||
<path d="M92 5V109.5" stroke="#6F42C1" strokeLinecap="round" />
|
||||
<g filter="url(#filter2_f_3106_8112)">
|
||||
<circle cx="92" cy="57" r="12" fill="#6F42C1" />
|
||||
</g>
|
||||
<circle cx="92" cy="57" r="12" fill="#6F42C1" />
|
||||
<g filter="url(#filter3_f_3106_8112)">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M89.9091 61.9119C89.7089 59.2881 87.6238 57.203 85 57.0028C87.6238 56.8027 89.7089 54.7175 89.9091 52.0938C90.1093 54.7175 92.1944 56.8027 94.8182 57.0028C92.1944 57.203 90.1093 59.2881 89.9091 61.9119Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M89.9091 61.9119C89.7089 59.2881 87.6238 57.203 85 57.0028C87.6238 56.8027 89.7089 54.7175 89.9091 52.0938C90.1093 54.7175 92.1944 56.8027 94.8182 57.0028C92.1944 57.203 90.1093 59.2881 89.9091 61.9119Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
<g filter="url(#filter4_f_3106_8112)">
|
||||
<path
|
||||
d="M96.0444 65.5888C95.9374 64.809 95.4601 63.3226 93.5898 63.1342C95.4601 62.9458 95.9374 61.4595 96.0444 60.6797C96.2328 62.5499 97.7191 63.0272 98.4989 63.1342C97.7191 63.2412 96.2328 63.7185 96.0444 65.5888Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
d="M96.0444 65.5888C95.9374 64.809 95.4601 63.3226 93.5898 63.1342C95.4601 62.9458 95.9374 61.4595 96.0444 60.6797C96.2328 62.5499 97.7191 63.0272 98.4989 63.1342C97.7191 63.2412 96.2328 63.7185 96.0444 65.5888Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
<g filter="url(#filter5_f_3106_8112)">
|
||||
<path
|
||||
d="M96.0444 48.4062C96.2328 50.2765 97.7191 50.7538 98.4989 50.8608C97.7191 50.9678 96.2328 51.445 96.0444 53.3153C95.9374 52.5355 95.4601 51.0492 93.5898 50.8608C95.4601 50.6724 95.9374 49.1861 96.0444 48.4062Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
d="M96.0444 48.4062C96.2328 50.2765 97.7191 50.7538 98.4989 50.8608C97.7191 50.9678 96.2328 51.445 96.0444 53.3153C95.9374 52.5355 95.4601 51.0492 93.5898 50.8608C95.4601 50.6724 95.9374 49.1861 96.0444 48.4062Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
<g filter="url(#filter6_d_3106_8112)">
|
||||
<path
|
||||
d="M157 26H172C175.314 26 178 28.6863 178 32V82C178 85.3137 175.314 88 172 88H157V26Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
<path
|
||||
d="M172 26.5C175.038 26.5 177.5 28.9624 177.5 32V82C177.5 85.0376 175.038 87.5 172 87.5H157.5V26.5H172Z"
|
||||
stroke="#E5E5EA"
|
||||
/>
|
||||
</g>
|
||||
<g filter="url(#filter7_d_3106_8112)">
|
||||
<path
|
||||
d="M25 87H10C6.68629 87 4 84.3137 4 81L4 31C4 27.6863 6.68629 25 10 25H25L25 87Z"
|
||||
fill="#FCFDFD"
|
||||
/>
|
||||
<path
|
||||
d="M10 86.5C6.96243 86.5 4.5 84.0376 4.5 81L4.5 31C4.5 27.9624 6.96244 25.5 10 25.5H24.5L24.5 86.5H10Z"
|
||||
stroke="#E5E5EA"
|
||||
/>
|
||||
</g>
|
||||
<rect
|
||||
x="31.25"
|
||||
y="18.25"
|
||||
width="53.5"
|
||||
height="20.5"
|
||||
rx="3.75"
|
||||
fill="#F2F2F7"
|
||||
stroke="#C7C7CC"
|
||||
strokeWidth="0.5"
|
||||
/>
|
||||
<rect
|
||||
x="35.25"
|
||||
y="88.25"
|
||||
width="35.5"
|
||||
height="9.5"
|
||||
rx="3.75"
|
||||
fill="#F2F2F7"
|
||||
stroke="#C7C7CC"
|
||||
strokeWidth="0.5"
|
||||
/>
|
||||
<rect
|
||||
x="31.25"
|
||||
y="51.25"
|
||||
width="35.5"
|
||||
height="12.5"
|
||||
rx="3.75"
|
||||
fill="#F2F2F7"
|
||||
stroke="#C7C7CC"
|
||||
strokeWidth="0.5"
|
||||
/>
|
||||
<rect
|
||||
x="42.25"
|
||||
y="70.25"
|
||||
width="35.5"
|
||||
height="11.5"
|
||||
rx="3.75"
|
||||
fill="#F2F2F7"
|
||||
stroke="#C7C7CC"
|
||||
strokeWidth="0.5"
|
||||
/>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_d_3106_8112"
|
||||
x="20"
|
||||
y="4"
|
||||
width="142"
|
||||
height="114"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="4" />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="out" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.370833 0 0 0 0 0.370833 0 0 0 0 0.370833 0 0 0 0.11 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_3106_8112"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_3106_8112"
|
||||
result="shape"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter1_f_3106_8112"
|
||||
x="87.5"
|
||||
y="0.5"
|
||||
width="9"
|
||||
height="113.5"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="2"
|
||||
result="effect1_foregroundBlur_3106_8112"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter2_f_3106_8112"
|
||||
x="76"
|
||||
y="41"
|
||||
width="32"
|
||||
height="32"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="2"
|
||||
result="effect1_foregroundBlur_3106_8112"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter3_f_3106_8112"
|
||||
x="81"
|
||||
y="48.0938"
|
||||
width="17.8184"
|
||||
height="17.8203"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="2"
|
||||
result="effect1_foregroundBlur_3106_8112"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter4_f_3106_8112"
|
||||
x="89.5898"
|
||||
y="56.6797"
|
||||
width="12.9082"
|
||||
height="12.9062"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="2"
|
||||
result="effect1_foregroundBlur_3106_8112"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter5_f_3106_8112"
|
||||
x="89.5898"
|
||||
y="44.4062"
|
||||
width="12.9082"
|
||||
height="12.9062"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="2"
|
||||
result="effect1_foregroundBlur_3106_8112"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter6_d_3106_8112"
|
||||
x="153"
|
||||
y="26"
|
||||
width="29"
|
||||
height="70"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="4" />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="out" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.370833 0 0 0 0 0.370833 0 0 0 0 0.370833 0 0 0 0.11 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_3106_8112"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_3106_8112"
|
||||
result="shape"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter7_d_3106_8112"
|
||||
x="0"
|
||||
y="25"
|
||||
width="29"
|
||||
height="70"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="4" />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="out" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.370833 0 0 0 0 0.370833 0 0 0 0 0.370833 0 0 0 0.11 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_3106_8112"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_3106_8112"
|
||||
result="shape"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const ResizerIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="22"
|
||||
height="23"
|
||||
viewBox="0 0 22 23"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_3106_8243)">
|
||||
<g filter="url(#filter0_f_3106_8243)">
|
||||
<path
|
||||
d="M8.02644 3.65625V11.0201H3.89599L5.62315 9.28625L4.67923 8.34233L1.33203 11.6895L4.67923 15.0367L5.62315 14.0928L3.89599 12.359H8.02644V19.7228H9.36532V3.65625H8.02644ZM16.7292 8.34233L15.7853 9.28625L17.5124 11.0201H13.382V3.65625H12.0431V19.7228H13.382V12.359H17.5124L15.7853 14.0928L16.7292 15.0367L20.0764 11.6895L16.7292 8.34233Z"
|
||||
fill="var(--background-color-button)"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
d="M8.02644 3.65625V11.0201H3.89599L5.62315 9.28625L4.67923 8.34233L1.33203 11.6895L4.67923 15.0367L5.62315 14.0928L3.89599 12.359H8.02644V19.7228H9.36532V3.65625H8.02644ZM16.7292 8.34233L15.7853 9.28625L17.5124 11.0201H13.382V3.65625H12.0431V19.7228H13.382V12.359H17.5124L15.7853 14.0928L16.7292 15.0367L20.0764 11.6895L16.7292 8.34233Z"
|
||||
fill="var(--background-color-button)"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_f_3106_8243"
|
||||
x="-2.66797"
|
||||
y="-0.34375"
|
||||
width="26.7441"
|
||||
height="24.0703"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="2"
|
||||
result="effect1_foregroundBlur_3106_8243"
|
||||
/>
|
||||
</filter>
|
||||
<clipPath id="clip0_3106_8243">
|
||||
<rect
|
||||
width="21.4221"
|
||||
height="21.4221"
|
||||
fill="var(--background-color-button)"
|
||||
transform="translate(-0.00976562 0.984375)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const LayoutIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.99935 4.16406C9.5391 4.16406 9.16602 4.53716 9.16602 4.9974C9.16602 5.45763 9.5391 5.83073 9.99935 5.83073H16.666C17.1263 5.83073 17.4993 5.45763 17.4993 4.9974C17.4993 4.53716 17.1263 4.16406 16.666 4.16406H9.99935Z"
|
||||
fill="var(--text-color)"
|
||||
/>
|
||||
<path
|
||||
d="M5.83398 9.9974C5.83398 9.53715 6.20708 9.16406 6.66732 9.16406H13.334C13.7942 9.16406 14.1673 9.53715 14.1673 9.9974C14.1673 10.4576 13.7942 10.8307 13.334 10.8307H6.66732C6.20708 10.8307 5.83398 10.4576 5.83398 9.9974Z"
|
||||
fill="var(--text-color)"
|
||||
/>
|
||||
<path
|
||||
d="M2.5 14.9974C2.5 14.5371 2.8731 14.1641 3.33333 14.1641H10C10.4602 14.1641 10.8333 14.5371 10.8333 14.9974C10.8333 15.4576 10.4602 15.8307 10 15.8307H3.33333C2.8731 15.8307 2.5 15.4576 2.5 14.9974Z"
|
||||
fill="var(--text-color)"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ import useModuleStore from "../../../store/useModuleStore";
|
|||
import Widgets from "./visualization/widgets/Widgets";
|
||||
import Templates from "../../../modules/visualization/template/Templates";
|
||||
import Search from "../../ui/inputs/Search";
|
||||
import { useSaveVersion } from "../../../store/builder/store";
|
||||
|
||||
const SideBarLeft: React.FC = () => {
|
||||
const [activeOption, setActiveOption] = useState("Widgets");
|
||||
|
@ -15,6 +16,8 @@ const SideBarLeft: React.FC = () => {
|
|||
const { toggleUILeft } = useToggleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
|
||||
// Reset activeOption whenever activeModule changes
|
||||
useEffect(() => {
|
||||
setActiveOption("Outline");
|
||||
|
@ -31,7 +34,13 @@ const SideBarLeft: React.FC = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={`sidebar-left-wrapper ${toggleUILeft ? "open" : "closed"}`}>
|
||||
<div
|
||||
className={`sidebar-left-wrapper ${
|
||||
(toggleUILeft && !isVersionSaved) || activeModule !== "simulation"
|
||||
? "open"
|
||||
: "closed"
|
||||
}`}
|
||||
>
|
||||
<Header />
|
||||
{toggleUILeft && (
|
||||
<div className={`sidebar-left-container `}>
|
||||
|
@ -67,6 +76,8 @@ const SideBarLeft: React.FC = () => {
|
|||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
{!isVersionSaved && (
|
||||
<>
|
||||
<ToggleHeader
|
||||
options={["Outline"]}
|
||||
|
@ -77,6 +88,8 @@ const SideBarLeft: React.FC = () => {
|
|||
{activeOption === "Outline" ? <Outline /> : <Assets />}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
|
|
|
@ -14,6 +14,7 @@ import Visualization from "./visualization/Visualization";
|
|||
import Analysis from "./analysis/Analysis";
|
||||
import Simulations from "./simulation/Simulations";
|
||||
import useVersionHistoryStore, {
|
||||
useSaveVersion,
|
||||
useSelectedFloorItem,
|
||||
} from "../../../store/builder/store";
|
||||
import {
|
||||
|
@ -34,6 +35,7 @@ const SideBarRight: React.FC = () => {
|
|||
const { selectedEventData } = useSelectedEventData();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { viewVersionHistory, setVersionHistory } = useVersionHistoryStore();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
|
||||
// Reset activeList whenever activeModule changes
|
||||
useEffect(() => {
|
||||
|
@ -60,10 +62,14 @@ const SideBarRight: React.FC = () => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className={`sidebar-right-wrapper ${toggleUIRight ? "open" : "closed"}`}
|
||||
className={`sidebar-right-wrapper ${
|
||||
(toggleUIRight && !isVersionSaved) || activeModule !== "simulation"
|
||||
? "open"
|
||||
: "closed"
|
||||
}`}
|
||||
>
|
||||
<Header />
|
||||
{toggleUIRight && (
|
||||
{toggleUIRight && !isVersionSaved && (
|
||||
<div className="sidebar-actions-container">
|
||||
{activeModule !== "simulation" && (
|
||||
<button
|
||||
|
@ -170,6 +176,7 @@ const SideBarRight: React.FC = () => {
|
|||
)}
|
||||
{/* simulation */}
|
||||
{toggleUIRight &&
|
||||
!isVersionSaved &&
|
||||
!viewVersionHistory &&
|
||||
activeModule === "simulation" && (
|
||||
<>
|
||||
|
|
|
@ -22,8 +22,13 @@ import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertP
|
|||
import { deleteProductApi } from "../../../../services/simulation/deleteProductApi";
|
||||
import { renameProductApi } from "../../../../services/simulation/renameProductApi";
|
||||
import { determineExecutionMachineSequences } from "../../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
|
||||
import ComparePopUp from "../../../../modules/simulation/compare/compare";
|
||||
import { useCompareStore } from "../../../../store/builder/store";
|
||||
import ComparePopUp from "../../../ui/compare/compare";
|
||||
import {
|
||||
useCompareStore,
|
||||
useSaveVersion,
|
||||
} from "../../../../store/builder/store";
|
||||
import CompareLayOut from "../../../ui/compare/CompareLayOut";
|
||||
import useToggleStore from "../../../../store/useUIToggleStore";
|
||||
|
||||
interface Event {
|
||||
modelName: string;
|
||||
|
@ -60,7 +65,17 @@ const Simulations: React.FC = () => {
|
|||
const organization = email!.split("@")[1].split(".")[0];
|
||||
const [openObjects, setOpenObjects] = useState(true);
|
||||
const [processes, setProcesses] = useState<Event[][]>();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
|
||||
const { comparePopUp, setComparePopUp } = useCompareStore();
|
||||
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
|
||||
|
||||
const handleSaveVersion = () => {
|
||||
setIsVersionSaved(true);
|
||||
setComparePopUp(false);
|
||||
setToggleUI(false, false);
|
||||
};
|
||||
|
||||
const handleAddProduct = () => {
|
||||
const id = generateUUID();
|
||||
const name = `Product ${products.length + 1}`;
|
||||
|
@ -241,9 +256,9 @@ const Simulations: React.FC = () => {
|
|||
Click '<span>Compare</span>' to review and analyze the layout
|
||||
differences between them.
|
||||
</div>
|
||||
<div className="input" onClick={() => setComparePopUp(true)}>
|
||||
<button className="input" onClick={() => setComparePopUp(true)}>
|
||||
<input type="button" value={"Compare"} className="submit" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -269,7 +284,7 @@ const Simulations: React.FC = () => {
|
|||
|
||||
{comparePopUp && (
|
||||
<RenderOverlay>
|
||||
<ComparePopUp />
|
||||
<ComparePopUp onClose={handleSaveVersion} />
|
||||
</RenderOverlay>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -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;
|
|
@ -1,10 +1,15 @@
|
|||
import React from "react";
|
||||
import { InfoIcon } from "../../../components/icons/ShortcutIcons";
|
||||
import { SaveDiskIcon } from "../../../components/icons/ExportCommonIcons";
|
||||
import React, { useState } from "react";
|
||||
import { InfoIcon } from "../../icons/ShortcutIcons";
|
||||
import { SaveDiskIcon } from "../../icons/ExportCommonIcons";
|
||||
import { useCompareStore } from "../../../store/builder/store";
|
||||
import OuterClick from "../../../utils/outerClick";
|
||||
import useToggleStore from "../../../store/useUIToggleStore";
|
||||
|
||||
const ComparePopUp = () => {
|
||||
interface ComparePopUpProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const ComparePopUp: React.FC<ComparePopUpProps> = ({ onClose }) => {
|
||||
const { setComparePopUp } = useCompareStore();
|
||||
|
||||
OuterClick({
|
||||
|
@ -47,7 +52,9 @@ const ComparePopUp = () => {
|
|||
|
||||
<div className="button-wrapper">
|
||||
<div className="button-group">
|
||||
<div className="save btn">Save & Continue</div>
|
||||
<button className="save btn" onClick={onClose}>
|
||||
Save & Continue
|
||||
</button>
|
||||
<div className="replace btn">Replace Existing Version</div>
|
||||
</div>
|
||||
<button
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import ModuleToggle from "../components/ui/ModuleToggle";
|
||||
import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft";
|
||||
import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
|
||||
|
@ -14,6 +14,7 @@ import {
|
|||
useZones,
|
||||
useLoadingProgress,
|
||||
useWidgetSubOption,
|
||||
useSaveVersion,
|
||||
} from "../store/builder/store";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
||||
|
@ -33,10 +34,14 @@ import LogList from "../components/ui/log/LogList";
|
|||
import Footer from "../components/footer/Footer";
|
||||
import SelectFloorPlan from "../components/temporary/SelectFloorPlan";
|
||||
import ControlsPlayer from "../components/layout/controls/ControlsPlayer";
|
||||
import CompareLayOut from "../components/ui/compare/CompareLayOut";
|
||||
import useToggleStore from "../store/useUIToggleStore";
|
||||
import RegularDropDown from "../components/ui/inputs/RegularDropDown";
|
||||
|
||||
const Project: React.FC = () => {
|
||||
let navigate = useNavigate();
|
||||
const echo = useLogger();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
|
||||
const { activeModule, setActiveModule } = useModuleStore();
|
||||
const { loadingProgress } = useLoadingProgress();
|
||||
|
@ -45,7 +50,13 @@ const Project: React.FC = () => {
|
|||
const { setFloorItems } = useFloorItems();
|
||||
const { setWallItems } = useWallItems();
|
||||
const { setZones } = useZones();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isVersionSaved) {
|
||||
setToggleUI(true, true);
|
||||
}
|
||||
}, [isVersionSaved]);
|
||||
useEffect(() => {
|
||||
setFloorItems([]);
|
||||
setWallItems([]);
|
||||
|
@ -83,6 +94,19 @@ const Project: React.FC = () => {
|
|||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { setFloatingWidget } = useFloatingWidget();
|
||||
|
||||
const [selectedLayout, setSelectedLayout] = useState<string | null>(null); // Track selected layout
|
||||
|
||||
const dummyLayouts = [
|
||||
{ id: 1, name: "Layout 1" },
|
||||
{ id: 2, name: "Layout 2" },
|
||||
{ id: 3, name: "Layout 3" },
|
||||
{ id: 4, name: "Layout 4" },
|
||||
];
|
||||
|
||||
const handleSelectLayout = (option: string) => {
|
||||
setSelectedLayout(option); // Set selected layout
|
||||
console.log("Selected layout:", option);
|
||||
};
|
||||
return (
|
||||
<div className="project-main">
|
||||
{!selectedUser && (
|
||||
|
@ -98,7 +122,9 @@ const Project: React.FC = () => {
|
|||
)}
|
||||
<RealTimeVisulization />
|
||||
{activeModule === "market" && <MarketPlace />}
|
||||
{activeModule !== "market" && !isPlaying && <Tools />}
|
||||
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
|
||||
<Tools />
|
||||
)}
|
||||
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
||||
{isPlaying && activeModule !== "simulation" && <ControlsPlayer />}
|
||||
|
||||
|
@ -137,6 +163,19 @@ const Project: React.FC = () => {
|
|||
</RenderOverlay>
|
||||
)}
|
||||
{activeModule !== "market" && !selectedUser && <Footer />}
|
||||
{isVersionSaved && activeModule === "simulation" && (
|
||||
<>
|
||||
<div className="initial-selectLayout-wrapper">
|
||||
<RegularDropDown
|
||||
header={selectedLayout ?? "Layout 1"}
|
||||
options={dummyLayouts.map((l) => l.name)} // Pass layout names as options
|
||||
onSelect={handleSelectLayout}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
<CompareLayOut dummyLayouts={dummyLayouts} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -472,8 +472,20 @@ interface CompareStore {
|
|||
}
|
||||
|
||||
export const useCompareStore = create<CompareStore>((set) => ({
|
||||
comparePopUp: false,
|
||||
comparePopUp: true,
|
||||
setComparePopUp: (value) => set({ comparePopUp: value }),
|
||||
toggleComparePopUp: () =>
|
||||
set((state) => ({ comparePopUp: !state.comparePopUp })),
|
||||
}));
|
||||
|
||||
// Define the types for the store state
|
||||
interface VersionStore {
|
||||
isVersionSaved: boolean;
|
||||
setIsVersionSaved: (value: boolean) => void;
|
||||
}
|
||||
|
||||
// Create the Zustand store
|
||||
export const useSaveVersion = create<VersionStore>((set) => ({
|
||||
isVersionSaved: false, // Default state
|
||||
setIsVersionSaved: (value: boolean) => set({ isVersionSaved: value }), // Function to update the state
|
||||
}));
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
@use "../abstracts/variables" as *;
|
||||
@use "../abstracts/mixins" as *;
|
||||
|
||||
.initial-selectLayout-wrapper {
|
||||
position: fixed;
|
||||
top: 100px;
|
||||
left: 40px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.compareLayOut-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
height: 100vh;
|
||||
background: var(--background-color);
|
||||
backdrop-filter: blur(20px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
animation: slideInFromRight 0.4s ease-out forwards;
|
||||
user-select: none;
|
||||
|
||||
|
||||
.selectLayout-wrapper {
|
||||
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.chooseLayout-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.resizer {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
@include flex-center;
|
||||
padding: 6px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translate(-50%, -50%);
|
||||
background: var(--background-color);
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: $box-shadow-heavy;
|
||||
border-radius: 50%;
|
||||
cursor: ew-resize;
|
||||
transition: transform 0.1s ease;
|
||||
z-index: 10;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.chooseLayout-wrapper {
|
||||
background: var(--background-color);
|
||||
backdrop-filter: blur(20px);
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: $box-shadow-medium;
|
||||
max-width: 80%;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
.icon {
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.value {
|
||||
margin-bottom: 15px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
padding: 8px 16px;
|
||||
background: var(--background-color-button);
|
||||
color: var(--icon-default-color-active);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.displayLayouts-container {
|
||||
max-width: 170px;
|
||||
height: auto;
|
||||
background: var(--background-color);
|
||||
backdrop-filter: blur(20px);
|
||||
padding: 6px;
|
||||
border-radius: 8px;
|
||||
box-shadow: $box-shadow-medium;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 100%;
|
||||
transform: translate(50%, -10px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
||||
.header {
|
||||
text-align: left;
|
||||
padding-top: 6px;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.search-wrapper {
|
||||
padding: 6px 0;
|
||||
|
||||
.search-container {
|
||||
padding: 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.layouts-container {
|
||||
.layout {
|
||||
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.layout-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
cursor: pointer;
|
||||
padding: 0 10px;
|
||||
background: none;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--highlight-text-color) !important;
|
||||
border-radius: 4px;
|
||||
|
||||
svg {
|
||||
path {
|
||||
|
||||
fill: var(--background-color-accent);
|
||||
}
|
||||
}
|
||||
|
||||
.layout {
|
||||
|
||||
color: var(--background-color-accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInFromRight {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
body.compare-layout-open {
|
||||
main {
|
||||
padding-right: 10px; // Adjust as needed
|
||||
transition: padding 0.3s ease;
|
||||
}
|
||||
}
|
|
@ -43,7 +43,6 @@
|
|||
.header {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
|
@ -104,7 +103,6 @@
|
|||
|
||||
.label-tab {
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status {
|
||||
|
@ -160,7 +158,6 @@
|
|||
.btn {
|
||||
padding: 10px 16px;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: 600;
|
||||
border-radius: 30px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
@ -191,7 +188,6 @@
|
|||
.cancel {
|
||||
color: red;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -665,7 +665,7 @@
|
|||
|
||||
path {
|
||||
stroke: var(--text-button-color);
|
||||
stroke-width: 1.3;
|
||||
strokeWidth: 1.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -936,7 +936,7 @@
|
|||
|
||||
path {
|
||||
stroke: var(--accent-color);
|
||||
stroke-width: 1.5px;
|
||||
strokeWidth: 1.5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -1253,8 +1253,10 @@
|
|||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-start;
|
||||
|
||||
input {
|
||||
width: fit-content;
|
||||
|
@ -1441,12 +1443,15 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-sidebar-ui-button {
|
||||
svg {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
right: 56px;
|
||||
|
||||
&::after {
|
||||
left: 100%;
|
||||
bottom: 50%;
|
||||
|
@ -1620,11 +1625,13 @@
|
|||
height: 100%;
|
||||
gap: 6px;
|
||||
padding: 2px;
|
||||
|
||||
.no-asset {
|
||||
text-align: center;
|
||||
margin: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.assets {
|
||||
width: 122px;
|
||||
height: 95px;
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
@use 'layout/toast';
|
||||
@use 'layout/skeleton';
|
||||
@use 'layout/compareLayoutPopUp';
|
||||
@use 'layout/compareLayout';
|
||||
|
||||
|
||||
// pages
|
||||
@use 'pages/dashboard';
|
||||
|
|
|
@ -71,6 +71,10 @@
|
|||
pointer-events: all;
|
||||
transition: all 0.3s linear;
|
||||
|
||||
&.bottom {
|
||||
bottom: var(--bottomWidth);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
@ -173,9 +177,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
bottom: 210px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -427,7 +428,7 @@
|
|||
|
||||
path {
|
||||
stroke: var(--text-button-color);
|
||||
stroke-width: 2;
|
||||
strokeWidth: 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,7 +440,7 @@
|
|||
|
||||
path {
|
||||
stroke: #f65648;
|
||||
stroke-width: 1.3;
|
||||
strokeWidth: 1.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
useActiveTool,
|
||||
useAddAction,
|
||||
useDeleteTool,
|
||||
useSaveVersion,
|
||||
useSelectedWallItem,
|
||||
useShortcutStore,
|
||||
useToggleView,
|
||||
|
@ -29,6 +30,7 @@ const KeyPressListener: React.FC = () => {
|
|||
const { setActiveTool } = useActiveTool();
|
||||
const { clearSelectedZone } = useSelectedZoneStore();
|
||||
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
||||
const { setIsVersionSaved } = useSaveVersion();
|
||||
|
||||
const isTextInput = (element: Element | null): boolean =>
|
||||
element instanceof HTMLInputElement ||
|
||||
|
@ -108,7 +110,6 @@ const KeyPressListener: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
const handleSidebarShortcuts = (key: string) => {
|
||||
if (activeModule === "market") return;
|
||||
|
||||
|
@ -144,12 +145,16 @@ const KeyPressListener: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
const handleKeyPress = (event: KeyboardEvent) => {
|
||||
if (isTextInput(document.activeElement)) return;
|
||||
|
||||
const keyCombination = detectModifierKeys(event);
|
||||
if (!keyCombination || ["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R") return;
|
||||
if (
|
||||
!keyCombination ||
|
||||
["F5", "F11", "F12"].includes(event.key) ||
|
||||
keyCombination === "Ctrl+R"
|
||||
)
|
||||
return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
|
@ -173,6 +178,7 @@ const KeyPressListener: React.FC = () => {
|
|||
setIsPlaying(false);
|
||||
clearSelectedZone();
|
||||
setShowShortcuts(false);
|
||||
setIsVersionSaved(false);
|
||||
}
|
||||
|
||||
if (keyCombination === "Ctrl+Shift+?") {
|
||||
|
@ -180,7 +186,11 @@ const KeyPressListener: React.FC = () => {
|
|||
}
|
||||
|
||||
// Placeholder for future implementation
|
||||
if (["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+H", "Ctrl+F"].includes(keyCombination)) {
|
||||
if (
|
||||
["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+H", "Ctrl+F"].includes(
|
||||
keyCombination
|
||||
)
|
||||
) {
|
||||
// Implement undo/redo/help/find/shortcuts
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue