v2-ui #89
|
@ -386,3 +386,452 @@ export function StorageCapacityIcon() {
|
||||||
</svg>
|
</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 Widgets from "./visualization/widgets/Widgets";
|
||||||
import Templates from "../../../modules/visualization/template/Templates";
|
import Templates from "../../../modules/visualization/template/Templates";
|
||||||
import Search from "../../ui/inputs/Search";
|
import Search from "../../ui/inputs/Search";
|
||||||
|
import { useSaveVersion } from "../../../store/builder/store";
|
||||||
|
|
||||||
const SideBarLeft: React.FC = () => {
|
const SideBarLeft: React.FC = () => {
|
||||||
const [activeOption, setActiveOption] = useState("Widgets");
|
const [activeOption, setActiveOption] = useState("Widgets");
|
||||||
|
@ -15,6 +16,8 @@ const SideBarLeft: React.FC = () => {
|
||||||
const { toggleUILeft } = useToggleStore();
|
const { toggleUILeft } = useToggleStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
|
||||||
|
const { isVersionSaved } = useSaveVersion();
|
||||||
|
|
||||||
// Reset activeOption whenever activeModule changes
|
// Reset activeOption whenever activeModule changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setActiveOption("Outline");
|
setActiveOption("Outline");
|
||||||
|
@ -31,7 +34,13 @@ const SideBarLeft: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`sidebar-left-wrapper ${toggleUILeft ? "open" : "closed"}`}>
|
<div
|
||||||
|
className={`sidebar-left-wrapper ${
|
||||||
|
(toggleUILeft && !isVersionSaved) || activeModule !== "simulation"
|
||||||
|
? "open"
|
||||||
|
: "closed"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<Header />
|
<Header />
|
||||||
{toggleUILeft && (
|
{toggleUILeft && (
|
||||||
<div className={`sidebar-left-container `}>
|
<div className={`sidebar-left-container `}>
|
||||||
|
@ -68,14 +77,18 @@ const SideBarLeft: React.FC = () => {
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ToggleHeader
|
{!isVersionSaved && (
|
||||||
options={["Outline"]}
|
<>
|
||||||
activeOption={activeOption}
|
<ToggleHeader
|
||||||
handleClick={handleToggleClick}
|
options={["Outline"]}
|
||||||
/>
|
activeOption={activeOption}
|
||||||
<div className="sidebar-left-content-container">
|
handleClick={handleToggleClick}
|
||||||
{activeOption === "Outline" ? <Outline /> : <Assets />}
|
/>
|
||||||
</div>
|
<div className="sidebar-left-content-container">
|
||||||
|
{activeOption === "Outline" ? <Outline /> : <Assets />}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import Visualization from "./visualization/Visualization";
|
||||||
import Analysis from "./analysis/Analysis";
|
import Analysis from "./analysis/Analysis";
|
||||||
import Simulations from "./simulation/Simulations";
|
import Simulations from "./simulation/Simulations";
|
||||||
import useVersionHistoryStore, {
|
import useVersionHistoryStore, {
|
||||||
|
useSaveVersion,
|
||||||
useSelectedFloorItem,
|
useSelectedFloorItem,
|
||||||
} from "../../../store/builder/store";
|
} from "../../../store/builder/store";
|
||||||
import {
|
import {
|
||||||
|
@ -34,6 +35,7 @@ const SideBarRight: React.FC = () => {
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
const { viewVersionHistory, setVersionHistory } = useVersionHistoryStore();
|
const { viewVersionHistory, setVersionHistory } = useVersionHistoryStore();
|
||||||
|
const { isVersionSaved } = useSaveVersion();
|
||||||
|
|
||||||
// Reset activeList whenever activeModule changes
|
// Reset activeList whenever activeModule changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -60,10 +62,14 @@ const SideBarRight: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`sidebar-right-wrapper ${toggleUIRight ? "open" : "closed"}`}
|
className={`sidebar-right-wrapper ${
|
||||||
|
(toggleUIRight && !isVersionSaved) || activeModule !== "simulation"
|
||||||
|
? "open"
|
||||||
|
: "closed"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<Header />
|
<Header />
|
||||||
{toggleUIRight && (
|
{toggleUIRight && !isVersionSaved && (
|
||||||
<div className="sidebar-actions-container">
|
<div className="sidebar-actions-container">
|
||||||
{activeModule !== "simulation" && (
|
{activeModule !== "simulation" && (
|
||||||
<button
|
<button
|
||||||
|
@ -170,6 +176,7 @@ const SideBarRight: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
{/* simulation */}
|
{/* simulation */}
|
||||||
{toggleUIRight &&
|
{toggleUIRight &&
|
||||||
|
!isVersionSaved &&
|
||||||
!viewVersionHistory &&
|
!viewVersionHistory &&
|
||||||
activeModule === "simulation" && (
|
activeModule === "simulation" && (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -4,305 +4,304 @@ import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
import { AIIcon } from "../../../icons/ExportCommonIcons";
|
import { AIIcon } from "../../../icons/ExportCommonIcons";
|
||||||
import LabeledButton from "../../../ui/inputs/LabledButton";
|
import LabeledButton from "../../../ui/inputs/LabledButton";
|
||||||
import {
|
import {
|
||||||
useAzimuth,
|
useAzimuth,
|
||||||
useElevation,
|
useElevation,
|
||||||
useLimitDistance,
|
useLimitDistance,
|
||||||
useRenderDistance,
|
useRenderDistance,
|
||||||
useResetCamera,
|
useResetCamera,
|
||||||
useRoofVisibility,
|
useRoofVisibility,
|
||||||
useSelectedWallItem,
|
useSelectedWallItem,
|
||||||
useShadows,
|
useShadows,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useTileDistance,
|
useTileDistance,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useWallVisibility,
|
useWallVisibility,
|
||||||
} from "../../../../store/builder/store";
|
} from "../../../../store/builder/store";
|
||||||
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
|
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
|
||||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||||
import { validateBBox } from "@turf/helpers";
|
import { validateBBox } from "@turf/helpers";
|
||||||
const GlobalProperties: React.FC = () => {
|
const GlobalProperties: React.FC = () => {
|
||||||
const { toggleView, setToggleView } = useToggleView();
|
const { toggleView, setToggleView } = useToggleView();
|
||||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||||
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
||||||
const { wallVisibility, setWallVisibility } = useWallVisibility();
|
const { wallVisibility, setWallVisibility } = useWallVisibility();
|
||||||
const { shadows, setShadows } = useShadows();
|
const { shadows, setShadows } = useShadows();
|
||||||
const { resetCamera, setResetCamera } = useResetCamera();
|
const { resetCamera, setResetCamera } = useResetCamera();
|
||||||
const { elevation, setElevation } = useElevation();
|
const { elevation, setElevation } = useElevation();
|
||||||
const { azimuth, setAzimuth } = useAzimuth();
|
const { azimuth, setAzimuth } = useAzimuth();
|
||||||
const { renderDistance, setRenderDistance } = useRenderDistance();
|
const { renderDistance, setRenderDistance } = useRenderDistance();
|
||||||
const { setPlaneValue, setGridValue, planeValue, gridValue } =
|
const { setPlaneValue, setGridValue, planeValue, gridValue } = useTileDistance();
|
||||||
useTileDistance();
|
const { socket } = useSocketStore();
|
||||||
useEffect(() => {}, [gridValue, planeValue]);
|
const { limitDistance, setLimitDistance } = useLimitDistance();
|
||||||
const { socket } = useSocketStore();
|
const [distance, setDistance] = useState<number>(40);
|
||||||
const { limitDistance, setLimitDistance } = useLimitDistance();
|
|
||||||
const [distance, setDistance] = useState<number>(40);
|
|
||||||
useEffect(() => {}, [limitDistance]);
|
|
||||||
|
|
||||||
const [limitGridDistance, setLimitGridDistance] = useState(false);
|
const [limitGridDistance, setLimitGridDistance] = useState(false);
|
||||||
const [gridDistance, setGridDistance] = useState<number>(3);
|
const [gridDistance, setGridDistance] = useState<number>(3);
|
||||||
|
|
||||||
const optimizeScene = async (value: any) => {
|
const optimizeScene = async (value: any) => {
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||||
|
|
||||||
const data = await setEnvironment(
|
const data = await setEnvironment(
|
||||||
organization,
|
organization,
|
||||||
localStorage.getItem("userId")!,
|
localStorage.getItem("userId")!,
|
||||||
wallVisibility,
|
wallVisibility,
|
||||||
roofVisibility,
|
roofVisibility,
|
||||||
shadows,
|
shadows,
|
||||||
30,
|
30,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
setRenderDistance(30);
|
setRenderDistance(30);
|
||||||
setLimitDistance(true);
|
setLimitDistance(true);
|
||||||
};
|
};
|
||||||
const limitRenderDistance = async () => {
|
|
||||||
const email = localStorage.getItem("email");
|
|
||||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
|
||||||
|
|
||||||
if (limitDistance) {
|
const limitRenderDistance = async () => {
|
||||||
let data = await setEnvironment(
|
const email = localStorage.getItem("email");
|
||||||
organization,
|
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||||
localStorage.getItem("userId")!,
|
|
||||||
wallVisibility,
|
if (limitDistance) {
|
||||||
roofVisibility,
|
let data = await setEnvironment(
|
||||||
shadows,
|
organization,
|
||||||
75,
|
localStorage.getItem("userId")!,
|
||||||
!limitDistance
|
wallVisibility,
|
||||||
);
|
roofVisibility,
|
||||||
setRenderDistance(75);
|
shadows,
|
||||||
} else {
|
75,
|
||||||
let data = await setEnvironment(
|
!limitDistance
|
||||||
organization,
|
);
|
||||||
localStorage.getItem("userId")!,
|
setRenderDistance(75);
|
||||||
wallVisibility,
|
} else {
|
||||||
roofVisibility,
|
let data = await setEnvironment(
|
||||||
shadows,
|
organization,
|
||||||
renderDistance,
|
localStorage.getItem("userId")!,
|
||||||
!limitDistance
|
wallVisibility,
|
||||||
);
|
roofVisibility,
|
||||||
|
shadows,
|
||||||
|
renderDistance,
|
||||||
|
!limitDistance
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setLimitDistance(!limitDistance);
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateDistance(value: number) {
|
||||||
|
setDistance(value);
|
||||||
|
setRenderDistance(value);
|
||||||
}
|
}
|
||||||
setLimitDistance(!limitDistance);
|
function updateGridDistance(value: number) {
|
||||||
};
|
setGridDistance(value);
|
||||||
|
// setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
||||||
function updateDistance(value: number) {
|
// setPlaneValue({ height: value * 100, width: value * 100 });
|
||||||
setDistance(value);
|
}
|
||||||
setRenderDistance(value);
|
function updatedGrid(value: number) {
|
||||||
}
|
// console.log(" (value * 100) / 4 : ", (value * 100) / 4);
|
||||||
function updateGridDistance(value: number) {
|
setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
||||||
setGridDistance(value);
|
setPlaneValue({ height: value * 100, width: value * 100 });
|
||||||
// setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
|
||||||
// setPlaneValue({ height: value * 100, width: value * 100 });
|
|
||||||
}
|
|
||||||
function updatedGrid(value: number) {
|
|
||||||
// console.log(" (value * 100) / 4 : ", (value * 100) / 4);
|
|
||||||
setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
|
||||||
setPlaneValue({ height: value * 100, width: value * 100 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedDist = async (value: number) => {
|
|
||||||
const email = localStorage.getItem("email");
|
|
||||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
|
||||||
setRenderDistance(value);
|
|
||||||
// setDistance(value);
|
|
||||||
const data = await setEnvironment(
|
|
||||||
organization,
|
|
||||||
localStorage.getItem("userId")!,
|
|
||||||
wallVisibility,
|
|
||||||
roofVisibility,
|
|
||||||
shadows,
|
|
||||||
value,
|
|
||||||
limitDistance
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to toggle roof visibility
|
|
||||||
const changeRoofVisibility = async () => {
|
|
||||||
const email = localStorage.getItem("email");
|
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
|
||||||
|
|
||||||
//using REST
|
|
||||||
const data = await setEnvironment(
|
|
||||||
organization,
|
|
||||||
localStorage.getItem("userId")!,
|
|
||||||
wallVisibility,
|
|
||||||
!roofVisibility,
|
|
||||||
shadows,
|
|
||||||
renderDistance,
|
|
||||||
limitDistance
|
|
||||||
);
|
|
||||||
//
|
|
||||||
|
|
||||||
//using Socket
|
|
||||||
// const visData = {
|
|
||||||
// organization: organization,
|
|
||||||
// userId: localStorage.getItem('userId')!,
|
|
||||||
// wallVisibility: wallVisibility,
|
|
||||||
// roofVisibility: !roofVisibility,
|
|
||||||
// shadowVisibility: shadows,
|
|
||||||
// socketId: socket.id
|
|
||||||
// };
|
|
||||||
// socket.emit('v1:Environment:set', visData)
|
|
||||||
|
|
||||||
setRoofVisibility(!roofVisibility); // Toggle roof visibility
|
|
||||||
};
|
|
||||||
// Function to toggle wall visibility
|
|
||||||
const changeWallVisibility = async () => {
|
|
||||||
const email = localStorage.getItem("email");
|
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
|
||||||
//using REST
|
|
||||||
const data = await setEnvironment(
|
|
||||||
organization,
|
|
||||||
localStorage.getItem("userId")!,
|
|
||||||
!wallVisibility,
|
|
||||||
roofVisibility,
|
|
||||||
shadows,
|
|
||||||
renderDistance,
|
|
||||||
limitDistance
|
|
||||||
);
|
|
||||||
//
|
|
||||||
|
|
||||||
//using Socket
|
|
||||||
// const visData = {
|
|
||||||
// organization: organization,
|
|
||||||
// userId: localStorage.getItem('userId')!,
|
|
||||||
// wallVisibility: !wallVisibility,
|
|
||||||
// roofVisibility: roofVisibility,
|
|
||||||
// shadowVisibility: shadows,
|
|
||||||
// socketId: socket.id
|
|
||||||
// };
|
|
||||||
// socket.emit('v1:Environment:set', visData)
|
|
||||||
|
|
||||||
setWallVisibility(!wallVisibility); // Toggle wall visibility
|
|
||||||
};
|
|
||||||
|
|
||||||
const shadowVisibility = async () => {
|
|
||||||
const email = localStorage.getItem("email");
|
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
|
||||||
//using REST
|
|
||||||
const data = await setEnvironment(
|
|
||||||
organization,
|
|
||||||
localStorage.getItem("userId")!,
|
|
||||||
wallVisibility,
|
|
||||||
roofVisibility,
|
|
||||||
!shadows,
|
|
||||||
renderDistance,
|
|
||||||
limitDistance
|
|
||||||
);
|
|
||||||
//
|
|
||||||
|
|
||||||
//using Socket
|
|
||||||
// const visData = {
|
|
||||||
// organization: organization,
|
|
||||||
// userId: localStorage.getItem('userId')!,
|
|
||||||
// wallVisibility: wallVisibility,
|
|
||||||
// roofVisibility: roofVisibility,
|
|
||||||
// shadowVisibility: !shadows,
|
|
||||||
// socketId: socket.id
|
|
||||||
// };
|
|
||||||
// socket.emit('v1:Environment:set', visData)
|
|
||||||
|
|
||||||
setShadows(!shadows);
|
|
||||||
};
|
|
||||||
const toggleResetCamera = () => {
|
|
||||||
if (!toggleView) {
|
|
||||||
setResetCamera(true); // Trigger reset camera action
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// function changeRenderDistance(e: any) {
|
const updatedDist = async (value: number) => {
|
||||||
// if (parseInt(e.target.value) < 20) {
|
const email = localStorage.getItem("email");
|
||||||
// setRenderDistance(20);
|
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||||
// } else if (parseInt(e.target.value) > 75) {
|
setRenderDistance(value);
|
||||||
// setRenderDistance(75);
|
// setDistance(value);
|
||||||
// } else {
|
const data = await setEnvironment(
|
||||||
// setRenderDistance(parseInt(e.target.value));
|
organization,
|
||||||
// }
|
localStorage.getItem("userId")!,
|
||||||
// }
|
wallVisibility,
|
||||||
return (
|
roofVisibility,
|
||||||
<div className="global-properties-container">
|
shadows,
|
||||||
<section>
|
value,
|
||||||
<div className="header">Environment</div>
|
limitDistance
|
||||||
<div className="optimize-button" onClick={optimizeScene}>
|
);
|
||||||
<AIIcon />
|
};
|
||||||
Optimize
|
|
||||||
|
// Function to toggle roof visibility
|
||||||
|
const changeRoofVisibility = async () => {
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
|
//using REST
|
||||||
|
const data = await setEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!,
|
||||||
|
wallVisibility,
|
||||||
|
!roofVisibility,
|
||||||
|
shadows,
|
||||||
|
renderDistance,
|
||||||
|
limitDistance
|
||||||
|
);
|
||||||
|
//
|
||||||
|
|
||||||
|
//using Socket
|
||||||
|
// const visData = {
|
||||||
|
// organization: organization,
|
||||||
|
// userId: localStorage.getItem('userId')!,
|
||||||
|
// wallVisibility: wallVisibility,
|
||||||
|
// roofVisibility: !roofVisibility,
|
||||||
|
// shadowVisibility: shadows,
|
||||||
|
// socketId: socket.id
|
||||||
|
// };
|
||||||
|
// socket.emit('v1:Environment:set', visData)
|
||||||
|
|
||||||
|
setRoofVisibility(!roofVisibility); // Toggle roof visibility
|
||||||
|
};
|
||||||
|
// Function to toggle wall visibility
|
||||||
|
const changeWallVisibility = async () => {
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
//using REST
|
||||||
|
const data = await setEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!,
|
||||||
|
!wallVisibility,
|
||||||
|
roofVisibility,
|
||||||
|
shadows,
|
||||||
|
renderDistance,
|
||||||
|
limitDistance
|
||||||
|
);
|
||||||
|
//
|
||||||
|
|
||||||
|
//using Socket
|
||||||
|
// const visData = {
|
||||||
|
// organization: organization,
|
||||||
|
// userId: localStorage.getItem('userId')!,
|
||||||
|
// wallVisibility: !wallVisibility,
|
||||||
|
// roofVisibility: roofVisibility,
|
||||||
|
// shadowVisibility: shadows,
|
||||||
|
// socketId: socket.id
|
||||||
|
// };
|
||||||
|
// socket.emit('v1:Environment:set', visData)
|
||||||
|
|
||||||
|
setWallVisibility(!wallVisibility); // Toggle wall visibility
|
||||||
|
};
|
||||||
|
|
||||||
|
const shadowVisibility = async () => {
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
//using REST
|
||||||
|
const data = await setEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!,
|
||||||
|
wallVisibility,
|
||||||
|
roofVisibility,
|
||||||
|
!shadows,
|
||||||
|
renderDistance,
|
||||||
|
limitDistance
|
||||||
|
);
|
||||||
|
//
|
||||||
|
|
||||||
|
//using Socket
|
||||||
|
// const visData = {
|
||||||
|
// organization: organization,
|
||||||
|
// userId: localStorage.getItem('userId')!,
|
||||||
|
// wallVisibility: wallVisibility,
|
||||||
|
// roofVisibility: roofVisibility,
|
||||||
|
// shadowVisibility: !shadows,
|
||||||
|
// socketId: socket.id
|
||||||
|
// };
|
||||||
|
// socket.emit('v1:Environment:set', visData)
|
||||||
|
|
||||||
|
setShadows(!shadows);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleResetCamera = () => {
|
||||||
|
if (!toggleView) {
|
||||||
|
setResetCamera(true); // Trigger reset camera action
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// function changeRenderDistance(e: any) {
|
||||||
|
// if (parseInt(e.target.value) < 20) {
|
||||||
|
// setRenderDistance(20);
|
||||||
|
// } else if (parseInt(e.target.value) > 75) {
|
||||||
|
// setRenderDistance(75);
|
||||||
|
// } else {
|
||||||
|
// setRenderDistance(parseInt(e.target.value));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return (
|
||||||
|
<div className="global-properties-container">
|
||||||
|
<section>
|
||||||
|
<div className="header">Environment</div>
|
||||||
|
<div className="optimize-button" onClick={optimizeScene}>
|
||||||
|
<AIIcon />
|
||||||
|
Optimize
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="split"></div>
|
||||||
|
|
||||||
|
<InputToggle
|
||||||
|
value={roofVisibility}
|
||||||
|
inputKey="1"
|
||||||
|
label="Roof Visibility"
|
||||||
|
onClick={changeRoofVisibility}
|
||||||
|
/>
|
||||||
|
<InputToggle
|
||||||
|
value={wallVisibility}
|
||||||
|
inputKey="2"
|
||||||
|
label="Wall Visibility"
|
||||||
|
onClick={changeWallVisibility}
|
||||||
|
/>
|
||||||
|
{/* <InputToggle
|
||||||
|
value={shadows}
|
||||||
|
inputKey="3"
|
||||||
|
label="Shadows Visibility"
|
||||||
|
onClick={shadowVisibility}
|
||||||
|
/> */}
|
||||||
|
<LabeledButton
|
||||||
|
label="Reset Camera"
|
||||||
|
onClick={toggleResetCamera}
|
||||||
|
value="Reset"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="split"></div>
|
||||||
|
{/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */}
|
||||||
|
<InputToggle
|
||||||
|
inputKey="4"
|
||||||
|
label="Limit Render Distance"
|
||||||
|
value={limitDistance}
|
||||||
|
// onClick={() => {
|
||||||
|
// setLimitDistance(!limitDistance);
|
||||||
|
// // setDistance(75);
|
||||||
|
// // setRenderDistance(75);
|
||||||
|
// }}
|
||||||
|
onClick={async () => {
|
||||||
|
await limitRenderDistance(); // Call the function here
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<InputRange
|
||||||
|
label="Distance"
|
||||||
|
disabled={!limitDistance}
|
||||||
|
value={renderDistance}
|
||||||
|
min={CONSTANTS.distanceConfig.minDistance}
|
||||||
|
max={CONSTANTS.distanceConfig.maxDistance}
|
||||||
|
onChange={(value: number) => updateDistance(value)}
|
||||||
|
onPointerUp={updatedDist}
|
||||||
|
key={"6"}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* <div className="split"></div>
|
||||||
|
<InputToggle
|
||||||
|
inputKey="6"
|
||||||
|
label="Display Grid"
|
||||||
|
value={limitGridDistance}
|
||||||
|
onClick={() => {
|
||||||
|
setLimitGridDistance(!limitGridDistance);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<InputRange
|
||||||
|
label="Tile Distance"
|
||||||
|
disabled={!limitGridDistance}
|
||||||
|
value={gridDistance}
|
||||||
|
key={"7"}
|
||||||
|
min={1}
|
||||||
|
max={5}
|
||||||
|
onChange={(value: number) => updateGridDistance(value)}
|
||||||
|
onPointerUp={updatedGrid}
|
||||||
|
/> */}
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
<div className="split"></div>
|
|
||||||
|
|
||||||
<InputToggle
|
|
||||||
value={roofVisibility}
|
|
||||||
inputKey="1"
|
|
||||||
label="Roof Visibility"
|
|
||||||
onClick={changeRoofVisibility}
|
|
||||||
/>
|
|
||||||
<InputToggle
|
|
||||||
value={wallVisibility}
|
|
||||||
inputKey="2"
|
|
||||||
label="Wall Visibility"
|
|
||||||
onClick={changeWallVisibility}
|
|
||||||
/>
|
|
||||||
{/* <InputToggle
|
|
||||||
value={shadows}
|
|
||||||
inputKey="3"
|
|
||||||
label="Shadows Visibility"
|
|
||||||
onClick={shadowVisibility}
|
|
||||||
/> */}
|
|
||||||
<LabeledButton
|
|
||||||
label="Reset Camera"
|
|
||||||
onClick={toggleResetCamera}
|
|
||||||
value="Reset"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="split"></div>
|
|
||||||
{/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */}
|
|
||||||
<InputToggle
|
|
||||||
inputKey="4"
|
|
||||||
label="Limit Render Distance"
|
|
||||||
value={limitDistance}
|
|
||||||
// onClick={() => {
|
|
||||||
// setLimitDistance(!limitDistance);
|
|
||||||
// // setDistance(75);
|
|
||||||
// // setRenderDistance(75);
|
|
||||||
// }}
|
|
||||||
onClick={async () => {
|
|
||||||
await limitRenderDistance(); // Call the function here
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<InputRange
|
|
||||||
label="Distance"
|
|
||||||
disabled={!limitDistance}
|
|
||||||
value={renderDistance}
|
|
||||||
min={CONSTANTS.distanceConfig.minDistance}
|
|
||||||
max={CONSTANTS.distanceConfig.maxDistance}
|
|
||||||
onChange={(value: number) => updateDistance(value)}
|
|
||||||
onPointerUp={updatedDist}
|
|
||||||
key={"6"}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* <div className="split"></div>
|
|
||||||
<InputToggle
|
|
||||||
inputKey="6"
|
|
||||||
label="Display Grid"
|
|
||||||
value={limitGridDistance}
|
|
||||||
onClick={() => {
|
|
||||||
setLimitGridDistance(!limitGridDistance);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<InputRange
|
|
||||||
label="Tile Distance"
|
|
||||||
disabled={!limitGridDistance}
|
|
||||||
value={gridDistance}
|
|
||||||
key={"7"}
|
|
||||||
min={1}
|
|
||||||
max={5}
|
|
||||||
onChange={(value: number) => updateGridDistance(value)}
|
|
||||||
onPointerUp={updatedGrid}
|
|
||||||
/> */}
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GlobalProperties;
|
export default GlobalProperties;
|
||||||
|
|
|
@ -22,8 +22,13 @@ import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertP
|
||||||
import { deleteProductApi } from "../../../../services/simulation/deleteProductApi";
|
import { deleteProductApi } from "../../../../services/simulation/deleteProductApi";
|
||||||
import { renameProductApi } from "../../../../services/simulation/renameProductApi";
|
import { renameProductApi } from "../../../../services/simulation/renameProductApi";
|
||||||
import { determineExecutionMachineSequences } from "../../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
|
import { determineExecutionMachineSequences } from "../../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
|
||||||
import ComparePopUp from "../../../../modules/simulation/compare/compare";
|
import ComparePopUp from "../../../ui/compare/compare";
|
||||||
import { useCompareStore } from "../../../../store/builder/store";
|
import {
|
||||||
|
useCompareStore,
|
||||||
|
useSaveVersion,
|
||||||
|
} from "../../../../store/builder/store";
|
||||||
|
import CompareLayOut from "../../../ui/compare/CompareLayOut";
|
||||||
|
import useToggleStore from "../../../../store/useUIToggleStore";
|
||||||
|
|
||||||
interface Event {
|
interface Event {
|
||||||
modelName: string;
|
modelName: string;
|
||||||
|
@ -60,7 +65,17 @@ const Simulations: React.FC = () => {
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
const [openObjects, setOpenObjects] = useState(true);
|
const [openObjects, setOpenObjects] = useState(true);
|
||||||
const [processes, setProcesses] = useState<Event[][]>();
|
const [processes, setProcesses] = useState<Event[][]>();
|
||||||
|
const { setToggleUI } = useToggleStore();
|
||||||
|
|
||||||
const { comparePopUp, setComparePopUp } = useCompareStore();
|
const { comparePopUp, setComparePopUp } = useCompareStore();
|
||||||
|
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
|
||||||
|
|
||||||
|
const handleSaveVersion = () => {
|
||||||
|
setIsVersionSaved(true);
|
||||||
|
setComparePopUp(false);
|
||||||
|
setToggleUI(false, false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleAddProduct = () => {
|
const handleAddProduct = () => {
|
||||||
const id = generateUUID();
|
const id = generateUUID();
|
||||||
const name = `Product ${products.length + 1}`;
|
const name = `Product ${products.length + 1}`;
|
||||||
|
@ -241,9 +256,9 @@ const Simulations: React.FC = () => {
|
||||||
Click '<span>Compare</span>' to review and analyze the layout
|
Click '<span>Compare</span>' to review and analyze the layout
|
||||||
differences between them.
|
differences between them.
|
||||||
</div>
|
</div>
|
||||||
<div className="input" onClick={() => setComparePopUp(true)}>
|
<button className="input" onClick={() => setComparePopUp(true)}>
|
||||||
<input type="button" value={"Compare"} className="submit" />
|
<input type="button" value={"Compare"} className="submit" />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -269,7 +284,7 @@ const Simulations: React.FC = () => {
|
||||||
|
|
||||||
{comparePopUp && (
|
{comparePopUp && (
|
||||||
<RenderOverlay>
|
<RenderOverlay>
|
||||||
<ComparePopUp />
|
<ComparePopUp onClose={handleSaveVersion} />
|
||||||
</RenderOverlay>
|
</RenderOverlay>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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 React, { useState } from "react";
|
||||||
import { InfoIcon } from "../../../components/icons/ShortcutIcons";
|
import { InfoIcon } from "../../icons/ShortcutIcons";
|
||||||
import { SaveDiskIcon } from "../../../components/icons/ExportCommonIcons";
|
import { SaveDiskIcon } from "../../icons/ExportCommonIcons";
|
||||||
import { useCompareStore } from "../../../store/builder/store";
|
import { useCompareStore } from "../../../store/builder/store";
|
||||||
import OuterClick from "../../../utils/outerClick";
|
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();
|
const { setComparePopUp } = useCompareStore();
|
||||||
|
|
||||||
OuterClick({
|
OuterClick({
|
||||||
|
@ -47,7 +52,9 @@ const ComparePopUp = () => {
|
||||||
|
|
||||||
<div className="button-wrapper">
|
<div className="button-wrapper">
|
||||||
<div className="button-group">
|
<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 className="replace btn">Replace Existing Version</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
|
@ -27,6 +27,7 @@ import addAssetModel from "../geomentries/assets/addAssetModel";
|
||||||
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
import { useEventsStore } from "../../../store/simulation/useEventsStore";
|
import { useEventsStore } from "../../../store/simulation/useEventsStore";
|
||||||
|
import { findEnvironment } from "../../../services/factoryBuilder/environment/findEnvironment";
|
||||||
|
|
||||||
const assetManagerWorker = new Worker(
|
const assetManagerWorker = new Worker(
|
||||||
new URL(
|
new URL(
|
||||||
|
@ -77,71 +78,77 @@ const FloorItemsGroup = ({
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
let totalAssets = 0;
|
findEnvironment(
|
||||||
let loadedAssets = 0;
|
organization,
|
||||||
|
localStorage.getItem("userId")!
|
||||||
|
).then((evnironMentData) => {
|
||||||
|
|
||||||
const updateLoadingProgress = (progress: number) => {
|
let totalAssets = 0;
|
||||||
if (progress < 100) {
|
let loadedAssets = 0;
|
||||||
setLoadingProgress(progress);
|
|
||||||
} else if (progress === 100) {
|
const updateLoadingProgress = (progress: number) => {
|
||||||
setTimeout(() => {
|
if (progress < 100) {
|
||||||
setLoadingProgress(100);
|
setLoadingProgress(progress);
|
||||||
|
} else if (progress === 100) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setLoadingProgress(0);
|
setLoadingProgress(100);
|
||||||
}, 1500);
|
setTimeout(() => {
|
||||||
}, 1000);
|
setLoadingProgress(0);
|
||||||
}
|
}, 1500);
|
||||||
};
|
}, 1000);
|
||||||
|
|
||||||
getFloorAssets(organization).then((data) => {
|
|
||||||
if (data.length > 0) {
|
|
||||||
const uniqueItems = (data as Types.FloorItems).filter(
|
|
||||||
(item, index, self) =>
|
|
||||||
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
|
||||||
);
|
|
||||||
totalAssets = uniqueItems.length;
|
|
||||||
if (totalAssets === 0) {
|
|
||||||
updateLoadingProgress(100);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
gltfLoaderWorker.postMessage({ floorItems: uniqueItems });
|
};
|
||||||
} else {
|
|
||||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
|
||||||
loadInitialFloorItems(
|
|
||||||
itemsGroup,
|
|
||||||
setFloorItems,
|
|
||||||
addEvent,
|
|
||||||
renderDistance
|
|
||||||
);
|
|
||||||
updateLoadingProgress(100);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
gltfLoaderWorker.onmessage = async (event) => {
|
getFloorAssets(organization).then((data) => {
|
||||||
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
if (data.length > 0) {
|
||||||
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
const uniqueItems = (data as Types.FloorItems).filter(
|
||||||
|
(item, index, self) =>
|
||||||
loader.load(blobUrl, (gltf) => {
|
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
||||||
URL.revokeObjectURL(blobUrl);
|
);
|
||||||
THREE.Cache.remove(blobUrl);
|
totalAssets = uniqueItems.length;
|
||||||
THREE.Cache.add(event.data.modelID, gltf);
|
if (totalAssets === 0) {
|
||||||
|
|
||||||
loadedAssets++;
|
|
||||||
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
|
||||||
updateLoadingProgress(progress);
|
|
||||||
|
|
||||||
if (loadedAssets === totalAssets) {
|
|
||||||
loadInitialFloorItems(
|
|
||||||
itemsGroup,
|
|
||||||
setFloorItems,
|
|
||||||
addEvent,
|
|
||||||
renderDistance
|
|
||||||
);
|
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
gltfLoaderWorker.postMessage({ floorItems: uniqueItems });
|
||||||
}
|
} else {
|
||||||
};
|
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||||
|
loadInitialFloorItems(
|
||||||
|
itemsGroup,
|
||||||
|
setFloorItems,
|
||||||
|
addEvent,
|
||||||
|
evnironMentData.renderDistance
|
||||||
|
);
|
||||||
|
updateLoadingProgress(100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
gltfLoaderWorker.onmessage = async (event) => {
|
||||||
|
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||||
|
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
||||||
|
|
||||||
|
loader.load(blobUrl, (gltf) => {
|
||||||
|
URL.revokeObjectURL(blobUrl);
|
||||||
|
THREE.Cache.remove(blobUrl);
|
||||||
|
THREE.Cache.add(event.data.modelID, gltf);
|
||||||
|
|
||||||
|
loadedAssets++;
|
||||||
|
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
||||||
|
updateLoadingProgress(progress);
|
||||||
|
|
||||||
|
if (loadedAssets === totalAssets) {
|
||||||
|
loadInitialFloorItems(
|
||||||
|
itemsGroup,
|
||||||
|
setFloorItems,
|
||||||
|
addEvent,
|
||||||
|
evnironMentData.renderDistance
|
||||||
|
);
|
||||||
|
updateLoadingProgress(100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -6,20 +6,22 @@ import { useSelectedProduct } from "../../../../../store/simulation/useSimulatio
|
||||||
import { useStorageUnitStore } from "../../../../../store/simulation/useStorageUnitStore";
|
import { useStorageUnitStore } from "../../../../../store/simulation/useStorageUnitStore";
|
||||||
import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore";
|
import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore";
|
||||||
import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore";
|
import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore";
|
||||||
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
|
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore";
|
||||||
|
|
||||||
export function useRetrieveHandler() {
|
export function useRetrieveHandler() {
|
||||||
const { addMaterial } = useMaterialStore();
|
const { addMaterial } = useMaterialStore();
|
||||||
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid } = useProductStore();
|
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = useProductStore();
|
||||||
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = useStorageUnitStore();
|
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = useStorageUnitStore();
|
||||||
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = useVehicleStore();
|
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = useVehicleStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { getArmBotById, addCurrentAction } = useArmBotStore();
|
const { getArmBotById, addCurrentAction } = useArmBotStore();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { speed } = useAnimationPlaySpeed();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
const { isReset } = useResetButtonStore();
|
const { isReset } = useResetButtonStore();
|
||||||
|
|
||||||
const [activeRetrievals, setActiveRetrievals] = useState<Map<string, { action: StorageAction, isProcessing: boolean, lastCheckTime: number }>>(new Map());
|
const [activeRetrievals, setActiveRetrievals] = useState<Map<string, { action: StorageAction, isProcessing: boolean, lastCheckTime: number }>>(new Map());
|
||||||
|
const retrievalTimeRef = useRef<Map<string, number>>(new Map());
|
||||||
|
|
||||||
const [initialDelayComplete, setInitialDelayComplete] = useState(false);
|
const [initialDelayComplete, setInitialDelayComplete] = useState(false);
|
||||||
const delayTimerRef = useRef<NodeJS.Timeout | null>(null);
|
const delayTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
@ -125,7 +127,26 @@ export function useRetrieveHandler() {
|
||||||
const armBot = getArmBotById(triggeredModel.modelUuid);
|
const armBot = getArmBotById(triggeredModel.modelUuid);
|
||||||
isIdle = (armBot && !armBot.isActive && armBot.state === 'idle' && !armBot.currentAction) || false;
|
isIdle = (armBot && !armBot.isActive && armBot.state === 'idle' && !armBot.currentAction) || false;
|
||||||
|
|
||||||
if (isIdle) {
|
if (!armBot) return;
|
||||||
|
if (!retrievalTimeRef.current.has(actionUuid) && isIdle) {
|
||||||
|
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const idleStartTime = retrievalTimeRef.current.get(actionUuid);
|
||||||
|
const minIdleTimeBeforeFirstRetrieval = 5000 / speed;
|
||||||
|
const minDelayBetweenRetrievals = 5000 / speed;
|
||||||
|
|
||||||
|
const canProceedFirstRetrieval = idleStartTime !== undefined &&
|
||||||
|
(currentTime - idleStartTime) >= minIdleTimeBeforeFirstRetrieval;
|
||||||
|
|
||||||
|
const lastRetrievalTime = retrievalTimeRef.current.get(`${actionUuid}_last`) ?? null;
|
||||||
|
const canProceedSubsequent = lastRetrievalTime === null ||
|
||||||
|
(currentTime - lastRetrievalTime) >= minDelayBetweenRetrievals;
|
||||||
|
|
||||||
|
const canProceed = lastRetrievalTime === null ? canProceedFirstRetrieval : canProceedSubsequent;
|
||||||
|
|
||||||
|
if (isIdle && canProceed) {
|
||||||
setActiveRetrievals(prev => {
|
setActiveRetrievals(prev => {
|
||||||
const newRetrievals = new Map(prev);
|
const newRetrievals = new Map(prev);
|
||||||
newRetrievals.set(actionUuid, {
|
newRetrievals.set(actionUuid, {
|
||||||
|
@ -138,42 +159,97 @@ export function useRetrieveHandler() {
|
||||||
|
|
||||||
const lastMaterial = getLastMaterial(storageUnit.modelUuid);
|
const lastMaterial = getLastMaterial(storageUnit.modelUuid);
|
||||||
if (lastMaterial) {
|
if (lastMaterial) {
|
||||||
const material = createNewMaterial(
|
|
||||||
lastMaterial.materialId,
|
|
||||||
lastMaterial.materialType,
|
|
||||||
storageUnit.point.action
|
|
||||||
);
|
|
||||||
|
|
||||||
if (material) {
|
if (retrieval.action.triggers[0].triggeredAsset.triggeredAction?.actionUuid) {
|
||||||
addCurrentAction(
|
const action = getActionByUuid(selectedProduct.productId, retrieval.action.triggers[0].triggeredAsset.triggeredAction.actionUuid);
|
||||||
triggeredModel.modelUuid,
|
if (action && action.triggers.length > 0 && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
|
||||||
retrieval.action.triggers[0].triggeredAsset.triggeredAction?.actionUuid ?? '',
|
const model = getEventByModelUuid(selectedProduct.productId, action.triggers[0].triggeredAsset.triggeredModel.modelUuid);
|
||||||
material.materialType,
|
if (model) {
|
||||||
material.materialId
|
if (model.type === 'vehicle') {
|
||||||
);
|
const vehicle = getVehicleById(model.modelUuid);
|
||||||
retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`);
|
if (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
|
||||||
|
const material = createNewMaterial(
|
||||||
|
lastMaterial.materialId,
|
||||||
|
lastMaterial.materialType,
|
||||||
|
storageUnit.point.action
|
||||||
|
);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
addCurrentAction(
|
||||||
|
triggeredModel.modelUuid,
|
||||||
|
retrieval.action.triggers[0].triggeredAsset.triggeredAction?.actionUuid ?? '',
|
||||||
|
material.materialType,
|
||||||
|
material.materialId
|
||||||
|
);
|
||||||
|
retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const material = createNewMaterial(
|
||||||
|
lastMaterial.materialId,
|
||||||
|
lastMaterial.materialType,
|
||||||
|
storageUnit.point.action
|
||||||
|
);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
addCurrentAction(
|
||||||
|
triggeredModel.modelUuid,
|
||||||
|
retrieval.action.triggers[0].triggeredAsset.triggeredAction?.actionUuid ?? '',
|
||||||
|
material.materialType,
|
||||||
|
material.materialId
|
||||||
|
);
|
||||||
|
retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setActiveRetrievals(prev => {
|
||||||
|
const newRetrievals = new Map(prev);
|
||||||
|
newRetrievals.set(actionUuid, {
|
||||||
|
...retrieval,
|
||||||
|
isProcessing: false,
|
||||||
|
lastCheckTime: currentTime,
|
||||||
|
});
|
||||||
|
return newRetrievals;
|
||||||
|
});
|
||||||
|
|
||||||
|
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
setActiveRetrievals(prev => {
|
}
|
||||||
const newRetrievals = new Map(prev);
|
} else if (!isIdle) {
|
||||||
newRetrievals.set(actionUuid, {
|
retrievalTimeRef.current.delete(actionUuid);
|
||||||
...retrieval,
|
|
||||||
isProcessing: false,
|
|
||||||
lastCheckTime: currentTime
|
|
||||||
});
|
|
||||||
return newRetrievals;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (triggeredModel.type === 'vehicle') {
|
} else if (triggeredModel.type === 'vehicle') {
|
||||||
const vehicle = getVehicleById(triggeredModel.modelUuid);
|
const vehicle = getVehicleById(triggeredModel.modelUuid);
|
||||||
isIdle = (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking) || false;
|
isIdle = (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) || false;
|
||||||
|
|
||||||
if (!vehicle) return;
|
if (!vehicle) return;
|
||||||
// const loadDuration = vehicle.point.action.unLoadDuration;
|
|
||||||
|
|
||||||
if (isIdle) {
|
const loadDuration = vehicle.point.action.unLoadDuration;
|
||||||
|
let minDelayBetweenRetrievals = (loadDuration * 1000) / speed;
|
||||||
|
const minIdleTimeBeforeFirstRetrieval = 3000 / speed;
|
||||||
|
|
||||||
|
if (!retrievalTimeRef.current.has(actionUuid) && isIdle) {
|
||||||
|
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const idleStartTime = retrievalTimeRef.current.get(actionUuid);
|
||||||
|
const lastRetrievalTime = retrievalTimeRef.current.get(`${actionUuid}_last`) ?? null;
|
||||||
|
|
||||||
|
const canProceedFirstRetrieval = idleStartTime !== undefined &&
|
||||||
|
(currentTime - idleStartTime) >= minIdleTimeBeforeFirstRetrieval;
|
||||||
|
|
||||||
|
const canProceedSubsequent = lastRetrievalTime === null ||
|
||||||
|
(currentTime - lastRetrievalTime) >= minDelayBetweenRetrievals;
|
||||||
|
|
||||||
|
const canProceed = lastRetrievalTime === null ? canProceedFirstRetrieval : canProceedSubsequent;
|
||||||
|
|
||||||
|
if (isIdle && canProceed) {
|
||||||
setActiveRetrievals(prev => {
|
setActiveRetrievals(prev => {
|
||||||
const newRetrievals = new Map(prev);
|
const newRetrievals = new Map(prev);
|
||||||
newRetrievals.set(actionUuid, {
|
newRetrievals.set(actionUuid, {
|
||||||
|
@ -208,12 +284,17 @@ export function useRetrieveHandler() {
|
||||||
newRetrievals.set(actionUuid, {
|
newRetrievals.set(actionUuid, {
|
||||||
...retrieval,
|
...retrieval,
|
||||||
isProcessing: false,
|
isProcessing: false,
|
||||||
lastCheckTime: currentTime
|
lastCheckTime: currentTime,
|
||||||
});
|
});
|
||||||
return newRetrievals;
|
return newRetrievals;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||||
|
retrievalTimeRef.current.set(`${actionUuid}_last`, currentTime);
|
||||||
|
} else if (!isIdle) {
|
||||||
|
retrievalTimeRef.current.delete(actionUuid);
|
||||||
|
retrievalTimeRef.current.delete(`${actionUuid}_last`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -234,7 +315,7 @@ export function useRetrieveHandler() {
|
||||||
newRetrievals.set(action.actionUuid, {
|
newRetrievals.set(action.actionUuid, {
|
||||||
action,
|
action,
|
||||||
isProcessing: false,
|
isProcessing: false,
|
||||||
lastCheckTime: performance.now()
|
lastCheckTime: performance.now(),
|
||||||
});
|
});
|
||||||
return newRetrievals;
|
return newRetrievals;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import MaterialInstances from './instances/materialInstances'
|
import MaterialInstances from './instances/materialInstances'
|
||||||
import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore';
|
import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore';
|
||||||
import { useMaterialStore } from '../../../store/simulation/useMaterialStore';
|
import { useMaterialStore } from '../../../store/simulation/useMaterialStore';
|
||||||
|
|
|
@ -228,11 +228,11 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.")
|
logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.")
|
||||||
}
|
}
|
||||||
// Moving to Pick to Drop position
|
// Moving to Pick to Drop position
|
||||||
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) {
|
else if (armBot && !armBot.isActive && armBot.state === "running" && currentPhase === "picking" && armBot.currentAction) {
|
||||||
requestAnimationFrame(firstFrame);
|
requestAnimationFrame(firstFrame);
|
||||||
}
|
}
|
||||||
//Moving to drop point to restPosition
|
//Moving to drop point to restPosition
|
||||||
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
|
else if (armBot && !armBot.isActive && armBot.state === "running" && currentPhase === "dropping" && armBot.currentAction) {
|
||||||
requestAnimationFrame(firstFrame);
|
requestAnimationFrame(firstFrame);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -270,14 +270,14 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
else if (armBot.isActive && armBot.state == "running" && currentPhase == "rest-to-start") {
|
else if (armBot.isActive && armBot.state == "running" && currentPhase == "rest-to-start") {
|
||||||
logStatus(armBot.modelUuid, "Callback triggered: pick.");
|
logStatus(armBot.modelUuid, "Callback triggered: pick.");
|
||||||
setArmBotActive(armBot.modelUuid, false)
|
setArmBotActive(armBot.modelUuid, false)
|
||||||
setArmBotState(armBot.modelUuid, "idle")
|
setArmBotState(armBot.modelUuid, "running")
|
||||||
setCurrentPhase("picking");
|
setCurrentPhase("picking");
|
||||||
setPath([])
|
setPath([])
|
||||||
}
|
}
|
||||||
else if (armBot.isActive && armBot.state == "running" && currentPhase == "start-to-end") {
|
else if (armBot.isActive && armBot.state == "running" && currentPhase == "start-to-end") {
|
||||||
logStatus(armBot.modelUuid, "Callback triggered: drop.");
|
logStatus(armBot.modelUuid, "Callback triggered: drop.");
|
||||||
setArmBotActive(armBot.modelUuid, false)
|
setArmBotActive(armBot.modelUuid, false)
|
||||||
setArmBotState(armBot.modelUuid, "idle")
|
setArmBotState(armBot.modelUuid, "running")
|
||||||
setCurrentPhase("dropping");
|
setCurrentPhase("dropping");
|
||||||
setPath([])
|
setPath([])
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,6 +414,10 @@ export function useTriggerHandler() {
|
||||||
|
|
||||||
handleAction(action, material.materialId);
|
handleAction(action, material.materialId);
|
||||||
}
|
}
|
||||||
|
} else if (action) {
|
||||||
|
setNextLocation(material.materialId, null)
|
||||||
|
|
||||||
|
handleAction(action, material.materialId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { NavMeshQuery } from '@recast-navigation/core';
|
||||||
import { useNavMesh } from '../../../../../store/builder/store';
|
import { useNavMesh } from '../../../../../store/builder/store';
|
||||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
||||||
|
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
|
||||||
|
import { useConveyorStore } from '../../../../../store/simulation/useConveyorStore';
|
||||||
import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
|
import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
|
||||||
import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore';
|
import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore';
|
||||||
import { useProductStore } from '../../../../../store/simulation/useProductStore';
|
import { useProductStore } from '../../../../../store/simulation/useProductStore';
|
||||||
|
@ -20,10 +22,12 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { removeMaterial, setEndTime } = useMaterialStore();
|
const { removeMaterial, setEndTime } = useMaterialStore();
|
||||||
const { getStorageUnitById } = useStorageUnitStore();
|
const { getStorageUnitById } = useStorageUnitStore();
|
||||||
|
const { getArmBotById } = useArmBotStore();
|
||||||
|
const { getConveyorById } = useConveyorStore();
|
||||||
const { triggerPointActions } = useTriggerHandler();
|
const { triggerPointActions } = useTriggerHandler();
|
||||||
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore();
|
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
|
const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial } = useVehicleStore();
|
||||||
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
|
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
const pauseTimeRef = useRef<number | null>(null);
|
const pauseTimeRef = useRef<number | null>(null);
|
||||||
|
@ -147,9 +151,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function startUnloadingProcess() {
|
function startUnloadingProcess() {
|
||||||
if (agvDetail.point.action.triggers.length > 0) {
|
if (agvDetail.point.action.triggers.length > 0) {
|
||||||
const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid);
|
const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid);
|
||||||
|
@ -159,19 +160,19 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||||
if (model.type === 'transfer') {
|
if (model.type === 'transfer') {
|
||||||
const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
|
const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
|
||||||
if (action) {
|
if (action) {
|
||||||
handleMaterialDropToConveyor(action);
|
handleMaterialDropToConveyor(model);
|
||||||
}
|
}
|
||||||
} else if (model.type === 'machine') {
|
} else if (model.type === 'machine') {
|
||||||
//
|
//
|
||||||
} else if (model.type === 'roboticArm') {
|
} else if (model.type === 'roboticArm') {
|
||||||
const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
|
const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
|
||||||
if (action) {
|
if (action) {
|
||||||
handleMaterialDropToArmBot(action);
|
handleMaterialDropToArmBot(model);
|
||||||
}
|
}
|
||||||
} else if (model.type === 'storageUnit') {
|
} else if (model.type === 'storageUnit') {
|
||||||
const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
|
const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
|
||||||
if (action) {
|
if (action) {
|
||||||
handleMaterialDropToStorageUnit(action);
|
handleMaterialDropToStorageUnit(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -186,25 +187,22 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMaterialDropToStorageUnit(action: Action) {
|
function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
|
||||||
if (action.triggers.length > 0 && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
|
if (model) {
|
||||||
const storageUnit = getStorageUnitById(action.triggers[0].triggeredAsset?.triggeredModel.modelUuid);
|
if (model.point.action.actionType === 'store') {
|
||||||
if (storageUnit) {
|
loopMaterialDropToStorage(
|
||||||
if (storageUnit.point.action.actionType === 'store') {
|
agvDetail.modelUuid,
|
||||||
handleMaterialDropToStorage(
|
agvDetail.currentLoad,
|
||||||
agvDetail.modelUuid,
|
agvDetail.point.action.unLoadDuration,
|
||||||
agvDetail.currentLoad,
|
model.modelUuid,
|
||||||
agvDetail.point.action.unLoadDuration,
|
model.point.action.storageCapacity,
|
||||||
storageUnit.modelUuid,
|
agvDetail.point.action
|
||||||
storageUnit.point.action.storageCapacity,
|
);
|
||||||
agvDetail.point.action
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMaterialDropToStorage(
|
function loopMaterialDropToStorage(
|
||||||
vehicleId: string,
|
vehicleId: string,
|
||||||
vehicleCurrentLoad: number,
|
vehicleCurrentLoad: number,
|
||||||
unLoadDuration: number,
|
unLoadDuration: number,
|
||||||
|
@ -262,24 +260,140 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMaterialDropToConveyor(action: Action) {
|
function handleMaterialDropToConveyor(model: ConveyorEventSchema) {
|
||||||
if (agvDetail.currentLoad > 1) {
|
const conveyor = getConveyorById(model.modelUuid);
|
||||||
//
|
if (conveyor) {
|
||||||
} else if (agvDetail.currentLoad === 1 && agvDetail.currentMaterials.length === 1) {
|
loopMaterialDropToConveyor(
|
||||||
triggerPointActions(action, agvDetail.currentMaterials[0].materialId);
|
agvDetail.modelUuid,
|
||||||
decrementVehicleLoad(agvDetail.modelUuid, 1);
|
agvDetail.currentLoad,
|
||||||
removeLastMaterial(agvDetail.modelUuid);
|
conveyor.modelUuid,
|
||||||
|
agvDetail.point.action.unLoadDuration,
|
||||||
|
agvDetail.point.action
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMaterialDropToArmBot(action: Action) {
|
function loopMaterialDropToConveyor(
|
||||||
if (agvDetail.currentLoad > 1) {
|
vehicleId: string,
|
||||||
//
|
vehicleCurrentLoad: number,
|
||||||
} else if (agvDetail.currentLoad === 1 && agvDetail.currentMaterials.length === 1) {
|
conveyorId: string,
|
||||||
triggerPointActions(action, agvDetail.currentMaterials[0].materialId);
|
unLoadDuration: number,
|
||||||
|
action: VehicleAction
|
||||||
|
) {
|
||||||
|
startTime = performance.now();
|
||||||
|
const fixedInterval = unLoadDuration * (1000 / speed);
|
||||||
|
|
||||||
|
const dropLoop = () => {
|
||||||
|
if (isPausedRef.current) {
|
||||||
|
pauseTimeRef.current ??= performance.now();
|
||||||
|
requestAnimationFrame(dropLoop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pauseTimeRef.current) {
|
||||||
|
const pauseDuration = performance.now() - pauseTimeRef.current;
|
||||||
|
startTime += pauseDuration;
|
||||||
|
pauseTimeRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elapsedTime = performance.now() - startTime;
|
||||||
|
const conveyor = getConveyorById(conveyorId);
|
||||||
|
if (elapsedTime >= fixedInterval) {
|
||||||
|
if (conveyor && !conveyor.isPaused && vehicleCurrentLoad > 0) {
|
||||||
|
decrementVehicleLoad(vehicleId, 1);
|
||||||
|
vehicleCurrentLoad -= 1;
|
||||||
|
|
||||||
|
const material = removeLastMaterial(vehicleId);
|
||||||
|
if (material) {
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vehicleCurrentLoad > 0) {
|
||||||
|
startTime = performance.now();
|
||||||
|
requestAnimationFrame(dropLoop);
|
||||||
|
}
|
||||||
|
} else if (!conveyor?.isActive) {
|
||||||
|
requestAnimationFrame(dropLoop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(dropLoop);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dropLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropToArmBot(model: RoboticArmEventSchema) {
|
||||||
|
const armBot = getArmBotById(model.modelUuid);
|
||||||
|
if (armBot && armBot.state === 'idle' && !armBot.isActive) {
|
||||||
|
loopMaterialDropToArmBot(
|
||||||
|
agvDetail.modelUuid,
|
||||||
|
agvDetail.currentLoad,
|
||||||
|
agvDetail.point.action.unLoadDuration,
|
||||||
|
model.modelUuid,
|
||||||
|
agvDetail.point.action
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loopMaterialDropToArmBot(
|
||||||
|
vehicleId: string,
|
||||||
|
vehicleCurrentLoad: number,
|
||||||
|
unLoadDuration: number,
|
||||||
|
armBotId: string,
|
||||||
|
action: VehicleAction
|
||||||
|
) {
|
||||||
|
startTime = performance.now();
|
||||||
|
const armBot = getArmBotById(armBotId);
|
||||||
|
|
||||||
|
if (!armBot || armBot.state !== 'idle' || armBot.isActive || vehicleCurrentLoad <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkIdleDuration = () => {
|
||||||
|
if (isPausedRef.current) {
|
||||||
|
pauseTimeRef.current ??= performance.now();
|
||||||
|
requestAnimationFrame(checkIdleDuration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pauseTimeRef.current) {
|
||||||
|
const pauseDuration = performance.now() - pauseTimeRef.current;
|
||||||
|
startTime += pauseDuration;
|
||||||
|
pauseTimeRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elapsedTime = performance.now() - startTime;
|
||||||
|
|
||||||
|
if (elapsedTime >= unLoadDuration * (1000 / speed)) {
|
||||||
|
const material = getLastMaterial(vehicleId);
|
||||||
|
if (material) {
|
||||||
|
vehicleCurrentLoad -= 1;
|
||||||
|
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
|
||||||
|
if (vehicleCurrentLoad > 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const waitForNextTransfer = () => {
|
||||||
|
const currentArmBot = getArmBotById(armBotId);
|
||||||
|
if (currentArmBot && currentArmBot.state === 'idle' && !currentArmBot.isActive) {
|
||||||
|
startTime = performance.now();
|
||||||
|
loopMaterialDropToArmBot(vehicleId, vehicleCurrentLoad, unLoadDuration, armBotId, action);
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextTransfer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForNextTransfer();
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(checkIdleDuration);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkIdleDuration();
|
||||||
|
}
|
||||||
|
|
||||||
function handleMaterialDropByDefault(droppedMaterial: number) {
|
function handleMaterialDropByDefault(droppedMaterial: number) {
|
||||||
if (isPausedRef.current) {
|
if (isPausedRef.current) {
|
||||||
pauseTimeRef.current ??= performance.now();
|
pauseTimeRef.current ??= performance.now();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import ModuleToggle from "../components/ui/ModuleToggle";
|
import ModuleToggle from "../components/ui/ModuleToggle";
|
||||||
import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft";
|
import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft";
|
||||||
import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
|
import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
|
||||||
|
@ -14,6 +14,7 @@ import {
|
||||||
useZones,
|
useZones,
|
||||||
useLoadingProgress,
|
useLoadingProgress,
|
||||||
useWidgetSubOption,
|
useWidgetSubOption,
|
||||||
|
useSaveVersion,
|
||||||
} from "../store/builder/store";
|
} from "../store/builder/store";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
||||||
|
@ -33,10 +34,14 @@ import LogList from "../components/ui/log/LogList";
|
||||||
import Footer from "../components/footer/Footer";
|
import Footer from "../components/footer/Footer";
|
||||||
import SelectFloorPlan from "../components/temporary/SelectFloorPlan";
|
import SelectFloorPlan from "../components/temporary/SelectFloorPlan";
|
||||||
import ControlsPlayer from "../components/layout/controls/ControlsPlayer";
|
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 = () => {
|
const Project: React.FC = () => {
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const echo = useLogger();
|
const echo = useLogger();
|
||||||
|
const { setToggleUI } = useToggleStore();
|
||||||
|
|
||||||
const { activeModule, setActiveModule } = useModuleStore();
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
const { loadingProgress } = useLoadingProgress();
|
const { loadingProgress } = useLoadingProgress();
|
||||||
|
@ -45,7 +50,13 @@ const Project: React.FC = () => {
|
||||||
const { setFloorItems } = useFloorItems();
|
const { setFloorItems } = useFloorItems();
|
||||||
const { setWallItems } = useWallItems();
|
const { setWallItems } = useWallItems();
|
||||||
const { setZones } = useZones();
|
const { setZones } = useZones();
|
||||||
|
const { isVersionSaved } = useSaveVersion();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isVersionSaved) {
|
||||||
|
setToggleUI(true, true);
|
||||||
|
}
|
||||||
|
}, [isVersionSaved]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFloorItems([]);
|
setFloorItems([]);
|
||||||
setWallItems([]);
|
setWallItems([]);
|
||||||
|
@ -83,6 +94,19 @@ const Project: React.FC = () => {
|
||||||
const { selectedZone } = useSelectedZoneStore();
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
const { setFloatingWidget } = useFloatingWidget();
|
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 (
|
return (
|
||||||
<div className="project-main">
|
<div className="project-main">
|
||||||
{!selectedUser && (
|
{!selectedUser && (
|
||||||
|
@ -98,7 +122,9 @@ const Project: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
<RealTimeVisulization />
|
<RealTimeVisulization />
|
||||||
{activeModule === "market" && <MarketPlace />}
|
{activeModule === "market" && <MarketPlace />}
|
||||||
{activeModule !== "market" && !isPlaying && <Tools />}
|
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
|
||||||
|
<Tools />
|
||||||
|
)}
|
||||||
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
||||||
{isPlaying && activeModule !== "simulation" && <ControlsPlayer />}
|
{isPlaying && activeModule !== "simulation" && <ControlsPlayer />}
|
||||||
|
|
||||||
|
@ -137,6 +163,19 @@ const Project: React.FC = () => {
|
||||||
</RenderOverlay>
|
</RenderOverlay>
|
||||||
)}
|
)}
|
||||||
{activeModule !== "market" && !selectedUser && <Footer />}
|
{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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -472,8 +472,20 @@ interface CompareStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useCompareStore = create<CompareStore>((set) => ({
|
export const useCompareStore = create<CompareStore>((set) => ({
|
||||||
comparePopUp: false,
|
comparePopUp: true,
|
||||||
setComparePopUp: (value) => set({ comparePopUp: value }),
|
setComparePopUp: (value) => set({ comparePopUp: value }),
|
||||||
toggleComparePopUp: () =>
|
toggleComparePopUp: () =>
|
||||||
set((state) => ({ comparePopUp: !state.comparePopUp })),
|
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
|
||||||
|
}));
|
||||||
|
|
|
@ -25,6 +25,7 @@ interface VehiclesStore {
|
||||||
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
|
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
|
||||||
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void;
|
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void;
|
||||||
removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
|
removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
|
||||||
|
getLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
|
||||||
clearCurrentMaterials: (modelUuid: string) => void;
|
clearCurrentMaterials: (modelUuid: string) => void;
|
||||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
@ -179,6 +180,22 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
return removedMaterial;
|
return removedMaterial;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getLastMaterial: (modelUuid) => {
|
||||||
|
let removedMaterial: { materialId: string; materialType: string; } | undefined;
|
||||||
|
set((state) => {
|
||||||
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
|
if (vehicle) {
|
||||||
|
if (vehicle.currentMaterials.length > 0) {
|
||||||
|
removedMaterial = {
|
||||||
|
materialId: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialId,
|
||||||
|
materialType: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return removedMaterial;
|
||||||
|
},
|
||||||
|
|
||||||
clearCurrentMaterials: (modelUuid) => {
|
clearCurrentMaterials: (modelUuid) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
@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 {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
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;
|
||||||
|
|
||||||
|
// transition: padding 0.3s ease;
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -43,7 +43,6 @@
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +103,6 @@
|
||||||
|
|
||||||
.label-tab {
|
.label-tab {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
|
@ -160,7 +158,6 @@
|
||||||
.btn {
|
.btn {
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
font-weight: 600;
|
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
@ -191,7 +188,6 @@
|
||||||
.cancel {
|
.cancel {
|
||||||
color: red;
|
color: red;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -665,7 +665,7 @@
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: var(--text-button-color);
|
stroke: var(--text-button-color);
|
||||||
stroke-width: 1.3;
|
strokeWidth: 1.3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -936,7 +936,7 @@
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: var(--accent-color);
|
stroke: var(--accent-color);
|
||||||
stroke-width: 1.5px;
|
strokeWidth: 1.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -1253,8 +1253,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
@ -1441,12 +1443,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-sidebar-ui-button {
|
.toggle-sidebar-ui-button {
|
||||||
svg {
|
svg {
|
||||||
transform: scaleX(-1);
|
transform: scaleX(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
right: 56px;
|
right: 56px;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
left: 100%;
|
left: 100%;
|
||||||
bottom: 50%;
|
bottom: 50%;
|
||||||
|
@ -1620,11 +1625,13 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
|
||||||
.no-asset {
|
.no-asset {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 12px;
|
margin: 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assets {
|
.assets {
|
||||||
width: 122px;
|
width: 122px;
|
||||||
height: 95px;
|
height: 95px;
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
@use 'layout/toast';
|
@use 'layout/toast';
|
||||||
@use 'layout/skeleton';
|
@use 'layout/skeleton';
|
||||||
@use 'layout/compareLayoutPopUp';
|
@use 'layout/compareLayoutPopUp';
|
||||||
|
@use 'layout/compareLayout';
|
||||||
|
|
||||||
|
|
||||||
// pages
|
// pages
|
||||||
@use 'pages/dashboard';
|
@use 'pages/dashboard';
|
||||||
|
|
|
@ -178,9 +178,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bottom {
|
|
||||||
bottom: 210px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +429,7 @@
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: var(--text-button-color);
|
stroke: var(--text-button-color);
|
||||||
stroke-width: 2;
|
strokeWidth: 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,7 +441,7 @@
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: #f65648;
|
stroke: #f65648;
|
||||||
stroke-width: 1.3;
|
strokeWidth: 1.3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,198 +2,217 @@ import React, { useEffect } from "react";
|
||||||
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
|
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
|
||||||
import useToggleStore from "../../store/useUIToggleStore";
|
import useToggleStore from "../../store/useUIToggleStore";
|
||||||
import {
|
import {
|
||||||
useActiveSubTool,
|
useActiveSubTool,
|
||||||
useActiveTool,
|
useActiveTool,
|
||||||
useAddAction,
|
useAddAction,
|
||||||
useDeleteTool,
|
useDeleteTool,
|
||||||
useSelectedWallItem,
|
useSaveVersion,
|
||||||
useShortcutStore,
|
useSelectedWallItem,
|
||||||
useToggleView,
|
useShortcutStore,
|
||||||
useToolMode,
|
useToggleView,
|
||||||
|
useToolMode,
|
||||||
} from "../../store/builder/store";
|
} from "../../store/builder/store";
|
||||||
import useCameraModeStore, { usePlayButtonStore } from "../../store/usePlayButtonStore";
|
import useCameraModeStore, {
|
||||||
|
usePlayButtonStore,
|
||||||
|
} from "../../store/usePlayButtonStore";
|
||||||
import { detectModifierKeys } from "./detectModifierKeys";
|
import { detectModifierKeys } from "./detectModifierKeys";
|
||||||
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
|
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
|
||||||
|
|
||||||
const KeyPressListener: React.FC = () => {
|
const KeyPressListener: React.FC = () => {
|
||||||
const { activeModule, setActiveModule } = useModuleStore();
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
const { setActiveSubTool } = useActiveSubTool();
|
const { setActiveSubTool } = useActiveSubTool();
|
||||||
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
|
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
|
||||||
const { setToggleThreeD } = useThreeDStore();
|
const { setToggleThreeD } = useThreeDStore();
|
||||||
const { setToolMode } = useToolMode();
|
const { setToolMode } = useToolMode();
|
||||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||||
const { toggleView, setToggleView } = useToggleView();
|
const { toggleView, setToggleView } = useToggleView();
|
||||||
const { setDeleteTool } = useDeleteTool();
|
const { setDeleteTool } = useDeleteTool();
|
||||||
const { setAddAction } = useAddAction();
|
const { setAddAction } = useAddAction();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
const { setActiveTool } = useActiveTool();
|
const { setActiveTool } = useActiveTool();
|
||||||
const { clearSelectedZone } = useSelectedZoneStore();
|
const { clearSelectedZone } = useSelectedZoneStore();
|
||||||
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
||||||
const { setWalkMode } = useCameraModeStore();
|
const { setWalkMode } = useCameraModeStore();
|
||||||
|
const { setIsVersionSaved } = useSaveVersion();
|
||||||
|
|
||||||
const isTextInput = (element: Element | null): boolean =>
|
const isTextInput = (element: Element | null): boolean =>
|
||||||
element instanceof HTMLInputElement ||
|
element instanceof HTMLInputElement ||
|
||||||
element instanceof HTMLTextAreaElement ||
|
element instanceof HTMLTextAreaElement ||
|
||||||
element?.getAttribute("contenteditable") === "true";
|
element?.getAttribute("contenteditable") === "true";
|
||||||
|
|
||||||
const handleModuleSwitch = (keyCombination: string) => {
|
const handleModuleSwitch = (keyCombination: string) => {
|
||||||
const modules: Record<string, string> = {
|
const modules: Record<string, string> = {
|
||||||
"1": "builder",
|
"1": "builder",
|
||||||
"2": "simulation",
|
"2": "simulation",
|
||||||
"3": "visualization",
|
"3": "visualization",
|
||||||
"4": "market",
|
"4": "market",
|
||||||
};
|
};
|
||||||
const module = modules[keyCombination];
|
const module = modules[keyCombination];
|
||||||
if (module && !toggleView) {
|
if (module && !toggleView) {
|
||||||
console.log("hi");
|
console.log("hi");
|
||||||
setActiveTool("cursor");
|
setActiveTool("cursor");
|
||||||
setActiveSubTool("cursor");
|
setActiveSubTool("cursor");
|
||||||
if (module === "market") setToggleUI(false, false);
|
if (module === "market") setToggleUI(false, false);
|
||||||
setActiveModule(module);
|
setActiveModule(module);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePrimaryTools = (key: string) => {
|
||||||
|
const toolMap: Record<string, string> = {
|
||||||
|
V: "cursor",
|
||||||
|
X: "delete",
|
||||||
|
H: "free-hand",
|
||||||
|
};
|
||||||
|
const tool = toolMap[key];
|
||||||
|
if (tool) {
|
||||||
|
setActiveTool(tool);
|
||||||
|
setActiveSubTool(tool);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBuilderShortcuts = (key: string) => {
|
||||||
|
if (activeModule !== "builder" || isPlaying) return;
|
||||||
|
|
||||||
|
if (key === "TAB") {
|
||||||
|
const toggleTo2D = toggleView;
|
||||||
|
setToggleView(!toggleTo2D);
|
||||||
|
setToggleThreeD(toggleTo2D);
|
||||||
|
setToggleUI(toggleTo2D, toggleTo2D);
|
||||||
|
if (toggleTo2D) {
|
||||||
|
setSelectedWallItem(null);
|
||||||
|
setDeleteTool(false);
|
||||||
|
setAddAction(null);
|
||||||
|
}
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setActiveSubTool("cursor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These should only apply in 2D view
|
||||||
|
const twoDToolConfigs: Record<string, { tool: string; mode: string }> = {
|
||||||
|
Q: { tool: "draw-wall", mode: "Wall" },
|
||||||
|
"6": { tool: "draw-wall", mode: "Wall" },
|
||||||
|
R: { tool: "draw-aisle", mode: "Aisle" },
|
||||||
|
"7": { tool: "draw-aisle", mode: "Aisle" },
|
||||||
|
E: { tool: "draw-zone", mode: "Zone" },
|
||||||
|
"8": { tool: "draw-zone", mode: "Zone" },
|
||||||
|
T: { tool: "draw-floor", mode: "Floor" },
|
||||||
|
"9": { tool: "draw-floor", mode: "Floor" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePrimaryTools = (key: string) => {
|
const config = twoDToolConfigs[key];
|
||||||
const toolMap: Record<string, string> = {
|
if (toggleView && config) {
|
||||||
V: "cursor",
|
setActiveTool(config.tool);
|
||||||
X: "delete",
|
setToolMode(config.mode);
|
||||||
H: "free-hand",
|
}
|
||||||
};
|
|
||||||
const tool = toolMap[key];
|
// Measurement tool should work in both 2D and 3D
|
||||||
if (tool) {
|
if (key === "M") {
|
||||||
setActiveTool(tool);
|
setActiveTool("measure");
|
||||||
setActiveSubTool(tool);
|
setToolMode("MeasurementScale");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSidebarShortcuts = (key: string) => {
|
||||||
|
if (activeModule === "market") return;
|
||||||
|
|
||||||
|
const updateLocalStorage = (left: boolean, right: boolean) => {
|
||||||
|
localStorage.setItem("navBarUiLeft", JSON.stringify(left));
|
||||||
|
localStorage.setItem("navBarUiRight", JSON.stringify(right));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBuilderShortcuts = (key: string) => {
|
switch (key) {
|
||||||
if (activeModule !== "builder" || isPlaying) return;
|
case "Ctrl+\\":
|
||||||
|
if (toggleUILeft === toggleUIRight) {
|
||||||
if (key === "TAB") {
|
const newState = !toggleUILeft;
|
||||||
const toggleTo2D = toggleView;
|
setToggleUI(newState, newState);
|
||||||
setToggleView(!toggleTo2D);
|
updateLocalStorage(newState, newState);
|
||||||
setToggleThreeD(toggleTo2D);
|
} else {
|
||||||
setToggleUI(toggleTo2D, toggleTo2D);
|
setToggleUI(true, true);
|
||||||
if (toggleTo2D) {
|
updateLocalStorage(true, true);
|
||||||
setSelectedWallItem(null);
|
|
||||||
setDeleteTool(false);
|
|
||||||
setAddAction(null);
|
|
||||||
}
|
|
||||||
setActiveTool("cursor");
|
|
||||||
setActiveSubTool("cursor");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// These should only apply in 2D view
|
case "Ctrl+]":
|
||||||
const twoDToolConfigs: Record<string, { tool: string; mode: string }> = {
|
setToggleUI(toggleUILeft, !toggleUIRight);
|
||||||
Q: { tool: "draw-wall", mode: "Wall" },
|
updateLocalStorage(toggleUILeft, !toggleUIRight);
|
||||||
"6": { tool: "draw-wall", mode: "Wall" },
|
break;
|
||||||
R: { tool: "draw-aisle", mode: "Aisle" },
|
|
||||||
"7": { tool: "draw-aisle", mode: "Aisle" },
|
|
||||||
E: { tool: "draw-zone", mode: "Zone" },
|
|
||||||
"8": { tool: "draw-zone", mode: "Zone" },
|
|
||||||
T: { tool: "draw-floor", mode: "Floor" },
|
|
||||||
"9": { tool: "draw-floor", mode: "Floor" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const config = twoDToolConfigs[key];
|
case "Ctrl+[":
|
||||||
if (toggleView && config) {
|
setToggleUI(!toggleUILeft, toggleUIRight);
|
||||||
setActiveTool(config.tool);
|
updateLocalStorage(!toggleUILeft, toggleUIRight);
|
||||||
setToolMode(config.mode);
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
// Measurement tool should work in both 2D and 3D
|
default:
|
||||||
if (key === "M") {
|
break;
|
||||||
setActiveTool("measure");
|
}
|
||||||
setToolMode("MeasurementScale");
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const handleKeyPress = (event: KeyboardEvent) => {
|
||||||
|
if (isTextInput(document.activeElement)) return;
|
||||||
|
|
||||||
const handleSidebarShortcuts = (key: string) => {
|
const keyCombination = detectModifierKeys(event);
|
||||||
if (activeModule === "market") return;
|
if (
|
||||||
|
!keyCombination ||
|
||||||
|
["F5", "F11", "F12"].includes(event.key) ||
|
||||||
|
keyCombination === "Ctrl+R"
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
const updateLocalStorage = (left: boolean, right: boolean) => {
|
event.preventDefault();
|
||||||
localStorage.setItem("navBarUiLeft", JSON.stringify(left));
|
|
||||||
localStorage.setItem("navBarUiRight", JSON.stringify(right));
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (key) {
|
// Shortcuts specific for sidebar visibility toggle and others specific to sidebar if added
|
||||||
case "Ctrl+\\":
|
handleSidebarShortcuts(keyCombination);
|
||||||
if (toggleUILeft === toggleUIRight) {
|
// Active module selection (builder, simulation, etc.)
|
||||||
const newState = !toggleUILeft;
|
handleModuleSwitch(keyCombination);
|
||||||
setToggleUI(newState, newState);
|
// Common editing tools: cursor | delete | free-hand
|
||||||
updateLocalStorage(newState, newState);
|
handlePrimaryTools(keyCombination);
|
||||||
} else {
|
// Shortcuts specific to the builder module (e.g., drawing and measurement tools)
|
||||||
setToggleUI(true, true);
|
handleBuilderShortcuts(keyCombination);
|
||||||
updateLocalStorage(true, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "Ctrl+]":
|
// Shortcut to enter play mode
|
||||||
setToggleUI(toggleUILeft, !toggleUIRight);
|
if (keyCombination === "Ctrl+P" && !toggleView) {
|
||||||
updateLocalStorage(toggleUILeft, !toggleUIRight);
|
setIsPlaying(true);
|
||||||
break;
|
}
|
||||||
|
|
||||||
case "Ctrl+[":
|
if (keyCombination === "ESCAPE") {
|
||||||
setToggleUI(!toggleUILeft, toggleUIRight);
|
setWalkMode(false);
|
||||||
updateLocalStorage(!toggleUILeft, toggleUIRight);
|
setActiveTool("cursor");
|
||||||
break;
|
setActiveSubTool("cursor");
|
||||||
|
setIsPlaying(false);
|
||||||
|
clearSelectedZone();
|
||||||
|
setShowShortcuts(false);
|
||||||
|
setIsVersionSaved(false);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
if (keyCombination === "Ctrl+Shift+?") {
|
||||||
break;
|
setShowShortcuts(!showShortcuts);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
// Placeholder for future implementation
|
||||||
|
if (
|
||||||
|
["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+H", "Ctrl+F"].includes(
|
||||||
|
keyCombination
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Implement undo/redo/help/find/shortcuts
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleKeyPress = (event: KeyboardEvent) => {
|
useEffect(() => {
|
||||||
if (isTextInput(document.activeElement)) return;
|
window.addEventListener("keydown", handleKeyPress);
|
||||||
|
return () => window.removeEventListener("keydown", handleKeyPress);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [
|
||||||
|
activeModule,
|
||||||
|
toggleUIRight,
|
||||||
|
toggleUILeft,
|
||||||
|
toggleView,
|
||||||
|
showShortcuts,
|
||||||
|
isPlaying,
|
||||||
|
]);
|
||||||
|
|
||||||
const keyCombination = detectModifierKeys(event);
|
return null;
|
||||||
if (!keyCombination || ["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R") return;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
// Shortcuts specific for sidebar visibility toggle and others specific to sidebar if added
|
|
||||||
handleSidebarShortcuts(keyCombination);
|
|
||||||
// Active module selection (builder, simulation, etc.)
|
|
||||||
handleModuleSwitch(keyCombination);
|
|
||||||
// Common editing tools: cursor | delete | free-hand
|
|
||||||
handlePrimaryTools(keyCombination);
|
|
||||||
// Shortcuts specific to the builder module (e.g., drawing and measurement tools)
|
|
||||||
handleBuilderShortcuts(keyCombination);
|
|
||||||
|
|
||||||
// Shortcut to enter play mode
|
|
||||||
if (keyCombination === "Ctrl+P" && !toggleView) {
|
|
||||||
setIsPlaying(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCombination === "ESCAPE") {
|
|
||||||
setWalkMode(false);
|
|
||||||
setActiveTool("cursor");
|
|
||||||
setActiveSubTool("cursor");
|
|
||||||
setIsPlaying(false);
|
|
||||||
clearSelectedZone();
|
|
||||||
setShowShortcuts(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCombination === "Ctrl+Shift+?") {
|
|
||||||
setShowShortcuts(!showShortcuts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Placeholder for future implementation
|
|
||||||
if (["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+H", "Ctrl+F"].includes(keyCombination)) {
|
|
||||||
// Implement undo/redo/help/find/shortcuts
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener("keydown", handleKeyPress);
|
|
||||||
return () => window.removeEventListener("keydown", handleKeyPress);
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [activeModule, toggleUIRight, toggleUILeft, toggleView, showShortcuts, isPlaying]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default KeyPressListener;
|
export default KeyPressListener;
|
||||||
|
|
Loading…
Reference in New Issue