diff --git a/app/package-lock.json b/app/package-lock.json index fa04c9f..3d5aea4 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -30,7 +30,6 @@ "glob": "^11.0.0", "gsap": "^3.12.5", "html2canvas": "^1.4.1", - "immer": "^10.1.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", @@ -2022,7 +2021,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2034,7 +2033,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4137,26 +4136,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4268,25 +4247,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true + "dev": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -9040,7 +9019,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true + "dev": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9917,7 +9896,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.3.1" } @@ -12747,10 +12726,9 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/immer": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", - "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", - "license": "MIT", + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -15281,7 +15259,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true + "dev": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -18012,16 +17990,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/react-dev-utils/node_modules/loader-utils": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", @@ -20759,7 +20727,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20802,7 +20770,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20814,7 +20782,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true + "dev": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21310,7 +21278,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22369,7 +22337,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6" } diff --git a/app/src/assets/gltf-glb/arm_ui_drop.glb b/app/src/assets/gltf-glb/arm_ui_drop.glb new file mode 100644 index 0000000..2a75e7e Binary files /dev/null and b/app/src/assets/gltf-glb/arm_ui_drop.glb differ diff --git a/app/src/assets/gltf-glb/arm_ui_pick.glb b/app/src/assets/gltf-glb/arm_ui_pick.glb new file mode 100644 index 0000000..979ade4 Binary files /dev/null and b/app/src/assets/gltf-glb/arm_ui_pick.glb differ diff --git a/app/src/components/icons/ContextMenuIcons.tsx b/app/src/components/icons/ContextMenuIcons.tsx index 217ad8f..f48cf3b 100644 --- a/app/src/components/icons/ContextMenuIcons.tsx +++ b/app/src/components/icons/ContextMenuIcons.tsx @@ -9,31 +9,31 @@ export function FlipXAxisIcon() { > @@ -52,31 +52,31 @@ export function FlipYAxisIcon() { > @@ -95,31 +95,31 @@ export function FlipZAxisIcon() { ); diff --git a/app/src/components/icons/DashboardIcon.tsx b/app/src/components/icons/DashboardIcon.tsx index f1f4d7d..314a3c8 100644 --- a/app/src/components/icons/DashboardIcon.tsx +++ b/app/src/components/icons/DashboardIcon.tsx @@ -9,13 +9,13 @@ export function NotificationIcon() { > @@ -34,7 +34,7 @@ export function HomeIcon() { > ); @@ -51,7 +51,7 @@ export function ProjectsIcon() { > ); @@ -70,103 +70,103 @@ export function TutorialsIcon() { cx="8.157" cy="8.35866" r="6.17928" - stroke="var(--text-color)" + stroke="var(--icon-default-color)" strokeWidth="0.562865" /> @@ -184,12 +184,12 @@ export function DocumentationIcon() { > @@ -208,7 +208,7 @@ export function HelpIcon() { @@ -236,17 +236,17 @@ export function LogoutIcon() { > diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index fcf7202..c78261e 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -9,7 +9,7 @@ export function SearchIcon() { > ); @@ -24,7 +24,7 @@ export function ArrowIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); } @@ -40,14 +40,14 @@ export function FocusIcon() { > @@ -65,7 +65,7 @@ export function LockIcon({ isLocked }: { isLocked: boolean }) { > @@ -80,7 +80,7 @@ export function LockIcon({ isLocked }: { isLocked: boolean }) { > @@ -100,7 +100,7 @@ export function EyeIcon({ isClosed }: { isClosed: boolean }) { @@ -119,13 +119,13 @@ export function EyeIcon({ isClosed }: { isClosed: boolean }) { > @@ -142,9 +142,9 @@ export function KebebIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - - - + + + ); } @@ -160,7 +160,7 @@ export function AddIcon() { > @@ -179,12 +179,12 @@ export function CloseIcon() { > @@ -203,11 +203,11 @@ export function SettingsIcon() { @@ -231,7 +231,7 @@ export function HelpIcon() { @@ -255,7 +255,7 @@ export function TrashIcon() { @@ -280,32 +280,32 @@ export function FilterIcon() { > @@ -324,7 +324,7 @@ export function EyeDroperIcon({ isActive }: { isActive: boolean }) { @@ -387,7 +387,7 @@ export function UndoIcon() { fillRule="evenodd" clipRule="evenodd" d="M3.76516 1.73483C3.91161 1.88128 3.91161 2.11872 3.76516 2.26516L2.90533 3.125H7.5C9.0878 3.125 10.375 4.41218 10.375 6C10.375 7.5878 9.0878 8.875 7.5 8.875H4C3.79289 8.875 3.625 8.7071 3.625 8.5C3.625 8.2929 3.79289 8.125 4 8.125H7.5C8.6736 8.125 9.625 7.1736 9.625 6C9.625 4.82639 8.6736 3.875 7.5 3.875H2.90533L3.76516 4.73483C3.91161 4.88128 3.91161 5.1187 3.76516 5.26515C3.61872 5.4116 3.38128 5.4116 3.23483 5.26515L1.73483 3.76516C1.58839 3.61872 1.58839 3.38128 1.73483 3.23483L3.23483 1.73483C3.38128 1.58839 3.61872 1.58839 3.76516 1.73483Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -406,7 +406,7 @@ export function RedoIcon() { fillRule="evenodd" clipRule="evenodd" d="M8.23484 1.73483C8.08839 1.88128 8.08839 2.11872 8.23484 2.26516L9.09467 3.125H4.5C2.9122 3.125 1.625 4.41218 1.625 6C1.625 7.5878 2.9122 8.875 4.5 8.875H8C8.20711 8.875 8.375 8.7071 8.375 8.5C8.375 8.2929 8.20711 8.125 8 8.125H4.5C3.3264 8.125 2.375 7.1736 2.375 6C2.375 4.82639 3.3264 3.875 4.5 3.875H9.09467L8.23484 4.73483C8.08839 4.88128 8.08839 5.1187 8.23484 5.26515C8.38128 5.4116 8.61872 5.4116 8.76517 5.26515L10.2652 3.76516C10.4116 3.61872 10.4116 3.38128 10.2652 3.23483L8.76517 1.73483C8.61872 1.58839 8.38128 1.58839 8.23484 1.73483Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -442,7 +442,7 @@ export function RemoveIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); } @@ -458,11 +458,11 @@ export function InfoIcon() { > ); @@ -512,21 +512,21 @@ export const KebabIcon = () => { cy="1.35112" rx="1.4993" ry="1.27477" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -545,7 +545,7 @@ export const DublicateIcon = () => { fillRule="evenodd" clipRule="evenodd" d="M14.3125 11.375C14.3125 11.7545 14.0045 12.0625 13.625 12.0625H8.125C7.7455 12.0625 7.4375 11.7545 7.4375 11.375V5.875C7.4375 5.4955 7.7455 5.1875 8.125 5.1875H13.625C14.0045 5.1875 14.3125 5.4955 14.3125 5.875V11.375ZM13.625 4.5H8.125C7.36566 4.5 6.75 5.11566 6.75 5.875V11.375C6.75 12.1343 7.36566 12.75 8.125 12.75H13.625C14.3843 12.75 15 12.1343 15 11.375V5.875C15 5.11566 14.3843 4.5 13.625 4.5ZM11.5625 14.125C11.5625 14.5045 11.2545 14.8125 10.875 14.8125H5.375C4.9955 14.8125 4.6875 14.5045 4.6875 14.125V8.625C4.6875 8.2455 4.9955 7.9375 5.375 7.9375H6.0625V7.25H5.375C4.61566 7.25 4 7.86566 4 8.625V14.125C4 14.8843 4.61566 15.5 5.375 15.5H10.875C11.6343 15.5 12.25 14.8843 12.25 14.125V13.4375H11.5625V14.125Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -562,34 +562,243 @@ export const DeleteIcon = () => { > ); }; + +export const HourlySimulationIcon = () => { + return ( + + + + ); +}; + +export const DailyProductionIcon = () => { + return ( + + + + + + ); +}; + +export const MonthlyROI = () => { + return ( + + + + ); +}; + +export const ExpandIcon = () => { + return ( + + + + + + ); +}; + +export const StartIcon = () => { + return ( + + + + + + + ); +}; + +export const EndIcon = () => { + return ( + + + + + + + ); +}; + +export const SpeedIcon = () => { + return ( + + + + ); +}; +// export const DublicateIcon = () => { +// return ( +// +// +// +// ); +// }; diff --git a/app/src/components/icons/ExportModuleIcons.tsx b/app/src/components/icons/ExportModuleIcons.tsx index fb2f566..1dda323 100644 --- a/app/src/components/icons/ExportModuleIcons.tsx +++ b/app/src/components/icons/ExportModuleIcons.tsx @@ -10,8 +10,8 @@ export function BuilderIcon({ isActive }: { isActive: boolean }) { > @@ -29,41 +29,41 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { > @@ -81,19 +81,19 @@ export function VisualizationIcon({ isActive }: { isActive: boolean }) { > @@ -112,20 +112,20 @@ export function CartIcon({ isActive }: { isActive: boolean }) { > diff --git a/app/src/components/icons/ExportToolsIcons.tsx b/app/src/components/icons/ExportToolsIcons.tsx index 478113c..4dc7a5b 100644 --- a/app/src/components/icons/ExportToolsIcons.tsx +++ b/app/src/components/icons/ExportToolsIcons.tsx @@ -11,13 +11,13 @@ export function ZoneIcon({ isActive }: { isActive: boolean }) { @@ -41,27 +41,27 @@ export function AsileIcon({ isActive }: { isActive: boolean }) { > ); @@ -87,36 +87,36 @@ export function FloorIcon({ isActive }: { isActive: boolean }) { ); @@ -134,7 +134,7 @@ export function WallIcon({ isActive }: { isActive: boolean }) { @@ -286,7 +286,7 @@ export function WindowIcon({ isActive }: { isActive: boolean }) { > @@ -421,7 +421,7 @@ export function CommentIcon({ isActive }: { isActive: boolean }) { > ) : ( @@ -502,17 +502,17 @@ export function DeleteIcon({ isActive }: { isActive: boolean }) { > @@ -552,7 +552,7 @@ export function CursorIcon({ isActive }: { isActive: boolean }) { > ) : ( @@ -585,7 +585,7 @@ export function PlayIcon({ isActive }: { isActive: boolean }) { ); @@ -603,7 +603,7 @@ export function PenIcon({ isActive }: { isActive: boolean }) { @@ -623,13 +623,13 @@ export function SaveTemplateIcon({ isActive }: { isActive: boolean }) { @@ -648,19 +648,19 @@ export function MeasureToolIcon({ isActive }: { isActive: boolean }) { > ); diff --git a/app/src/components/icons/HeaderIcons.tsx b/app/src/components/icons/HeaderIcons.tsx index 81f3690..ef02f02 100644 --- a/app/src/components/icons/HeaderIcons.tsx +++ b/app/src/components/icons/HeaderIcons.tsx @@ -65,15 +65,15 @@ export function AppDockIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - - - - - - - - - + + + + + + + + + ); } diff --git a/app/src/components/icons/Logo.tsx b/app/src/components/icons/Logo.tsx index d15398c..822e83e 100644 --- a/app/src/components/icons/Logo.tsx +++ b/app/src/components/icons/Logo.tsx @@ -7,108 +7,108 @@ export function LogoIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + diff --git a/app/src/components/icons/RealTimeVisulationIcons.tsx b/app/src/components/icons/RealTimeVisulationIcons.tsx index 84d8cca..d418247 100644 --- a/app/src/components/icons/RealTimeVisulationIcons.tsx +++ b/app/src/components/icons/RealTimeVisulationIcons.tsx @@ -10,43 +10,43 @@ export function CleanPannel() { diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index 4879ea4..b4aa881 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -9,13 +9,13 @@ export function AnalysisIcon({ isActive }: { isActive: boolean }) { > @@ -34,11 +34,11 @@ export function MechanicsIcon({ isActive }: { isActive: boolean }) { > ); @@ -55,15 +55,15 @@ export function PropertiesIcon({ isActive }: { isActive: boolean }) { > ); @@ -82,13 +82,13 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { fillRule="evenodd" clipRule="evenodd" d="M6.44104 7.04762C6.57815 6.98413 6.73614 6.98413 6.87325 7.04762L12.0161 9.42958C12.198 9.51377 12.3143 9.69589 12.3143 9.89624V15.8512C12.3143 16.0347 12.2165 16.2043 12.0577 16.2962L6.9148 19.2736C6.75547 19.3659 6.55881 19.3659 6.39949 19.2736L1.25661 16.2962C1.09779 16.2043 1 16.0347 1 15.8512V9.89624C1 9.69589 1.11635 9.51377 1.29815 9.42958L6.44104 7.04762ZM2.02857 10.7297L6.14286 12.794V17.9366L2.02857 15.5546V10.7297ZM7.17143 17.9366L11.2857 15.5546V10.7297L7.17143 12.794V17.9366ZM6.65714 11.9013L10.6163 9.91477L6.65714 8.08106L2.69798 9.91477L6.65714 11.9013Z" - fill={isActive ? "var(--primary-color)" : "var(--text-color)"} + fill={"var(--icon-default-color-active)"} /> ); @@ -107,21 +107,21 @@ export function ResetIcon() { > @@ -140,7 +140,7 @@ export function PlayStopIcon() { > @@ -159,7 +159,7 @@ export function ExitIcon() { > diff --git a/app/src/components/icons/analysis.tsx b/app/src/components/icons/analysis.tsx new file mode 100644 index 0000000..d081a86 --- /dev/null +++ b/app/src/components/icons/analysis.tsx @@ -0,0 +1,93 @@ +export function ThroughputSummaryIcon() { + return ( + + + + + ); +} +export function ProductionCapacityIcon() { + return ( + + + + + ); +} +export function ROISummaryIcon() { + return ( + + + + + + ); +} +export function PowerIcon() { + return ( + + + + + + + + + + + + ); +} diff --git a/app/src/components/icons/marketPlaceIcons.tsx b/app/src/components/icons/marketPlaceIcons.tsx index e69303f..6952ae1 100644 --- a/app/src/components/icons/marketPlaceIcons.tsx +++ b/app/src/components/icons/marketPlaceIcons.tsx @@ -29,13 +29,13 @@ export function DownloadIcon() { fillRule="evenodd" clipRule="evenodd" d="M2.5 11.875C2.84518 11.875 3.125 12.1548 3.125 12.5C3.125 13.6962 3.12633 14.5304 3.21096 15.1599C3.29317 15.7714 3.44354 16.0952 3.67418 16.3258C3.90481 16.5565 4.22863 16.7068 4.8401 16.7891C5.46956 16.8737 6.30383 16.875 7.5 16.875H12.5C13.6962 16.875 14.5304 16.8737 15.1599 16.7891C15.7714 16.7068 16.0952 16.5565 16.3258 16.3258C16.5565 16.0952 16.7068 15.7714 16.7891 15.1599C16.8737 14.5304 16.875 13.6962 16.875 12.5C16.875 12.1548 17.1548 11.875 17.5 11.875C17.8452 11.875 18.125 12.1548 18.125 12.5V12.5458C18.125 13.6854 18.125 14.604 18.0279 15.3265C17.9271 16.0766 17.7113 16.7081 17.2097 17.2097C16.7081 17.7113 16.0766 17.9271 15.3265 18.0279C14.604 18.125 13.6854 18.125 12.5458 18.125H7.45428C6.31462 18.125 5.39602 18.125 4.67354 18.0279C3.92345 17.9271 3.29189 17.7113 2.79029 17.2097C2.28869 16.7081 2.07295 16.0766 1.9721 15.3265C1.87497 14.604 1.87498 13.6854 1.875 12.5458C1.875 12.5305 1.875 12.5152 1.875 12.5C1.875 12.1548 2.15483 11.875 2.5 11.875Z" - fill="var(--primary-color)" + fill="var(--icon-default-color-active)" /> ); @@ -52,13 +52,13 @@ export function EyeIconBig() { > @@ -80,7 +80,7 @@ export function CommentsIcon() { fillRule="evenodd" clipRule="evenodd" d="M8 13C7.416 13 6.852 12.932 6.31 12.8165L3.956 14.2315L3.9875 11.912C2.183 10.827 1 9.033 1 7C1 3.6865 4.134 1 8 1C11.866 1 15 3.6865 15 7C15 10.314 11.866 13 8 13ZM8 0C3.582 0 0 3.1345 0 7C0 9.2095 1.1725 11.177 3 12.4595V16L6.5045 13.8735C6.9895 13.9535 7.4885 14 8 14C12.418 14 16 10.866 16 7C16 3.1345 12.418 0 8 0ZM11.5 5.5H4.5C4.224 5.5 4 5.724 4 6C4 6.2765 4.224 6.5 4.5 6.5H11.5C11.776 6.5 12 6.2765 12 6C12 5.724 11.776 5.5 11.5 5.5ZM10.5 8.5H5.5C5.224 8.5 5 8.7235 5 9C5 9.2765 5.224 9.5 5.5 9.5H10.5C10.776 9.5 11 9.2765 11 9C11 8.7235 10.776 8.5 10.5 8.5Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> diff --git a/app/src/components/layout/sidebarLeft/Outline.tsx b/app/src/components/layout/sidebarLeft/Outline.tsx index b7d5803..417f069 100644 --- a/app/src/components/layout/sidebarLeft/Outline.tsx +++ b/app/src/components/layout/sidebarLeft/Outline.tsx @@ -24,22 +24,26 @@ const Outline: React.FC = () => { ) : (
- - +
+ +
+
+ +
)} diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx index f9f48fb..a88baee 100644 --- a/app/src/components/layout/sidebarRight/Header.tsx +++ b/app/src/components/layout/sidebarRight/Header.tsx @@ -1,14 +1,14 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { AppDockIcon } from "../../icons/HeaderIcons"; import orgImg from "../../../assets/orgTemp.png"; import { useActiveUsers } from "../../../store/store"; -import { getAvatarColor } from "../../../functions/users/functions/getAvatarColor"; import { ActiveUser } from "../../../types/users"; import CollaborationPopup from "../../templates/CollaborationPopup"; +import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; const Header: React.FC = () => { const { activeUsers } = useActiveUsers(); - const userName = localStorage.getItem("userName") || "Anonymous"; + const userName = localStorage.getItem("userName") ?? "Anonymous"; const guestUsers: ActiveUser[] = activeUsers.filter( (user: ActiveUser) => user.userName !== userName @@ -23,14 +23,14 @@ const Header: React.FC = () => { )}
-
{ setUserManagement(true); }} > Share -
+ {/*
*/} diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index cb9b5dc..b2f25eb 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -49,6 +49,9 @@ const SideBarRight: React.FC = () => { setSubModule("simulations"); } } + if (activeModule !== "simulation") { + setSubModule("properties"); + } }, [activeModule, selectedEventData, selectedEventSphere, setSubModule]); return ( diff --git a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx index d806740..9d2889f 100644 --- a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx +++ b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx @@ -100,7 +100,7 @@ const Analysis: React.FC = () => {
Generate Report
-
+
Create Analysis
diff --git a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx index 01b4ab3..8cc47d7 100644 --- a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx +++ b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx @@ -22,7 +22,7 @@ const PositionInput: React.FC = ({ value2 = "number", disabled = false, // Default disabled value isEyedrop = false, // Default isEyedrop value - handleEyeDropClick = () => { }, // Default function for eye drop click + handleEyeDropClick = () => {}, // Default function for eye drop click }) => { return (
@@ -39,6 +39,7 @@ const PositionInput: React.FC = ({ disabled={disabled} // Apply disabled prop />
+
Y :
{
{/* Name */}
{selectedFloorItem.userData.name}
+
+ {}} + value1={selectedFloorItem.position.x.toFixed(5)} + value2={selectedFloorItem.position.z.toFixed(5)} + /> + {}} + value={parseFloat( + THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y).toFixed(5) + )} + /> +
- {}} - value1={selectedFloorItem.position.x.toFixed(5)} - value2={selectedFloorItem.position.z.toFixed(5)} - /> - {}} - value={parseFloat( - THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y).toFixed(5) - )} - /> +
+
Render settings
+ + +
-
- - - - -
User Data
- - {/* Map through userData and render InputWithDropDown for each entry */} - {userData.map((data) => ( -
- handleUserDataChange(data.id, newValue)} // Pass the change handler - /> -
handleRemoveUserData(data.id)} - > - +
+
User Data
+ {userData.map((data) => ( +
+ handleUserDataChange(data.id, newValue)} // Pass the change handler + /> +
handleRemoveUserData(data.id)} + > + +
-
- ))} + ))} - {/* Add new user data */} -
- + Add -
+ {/* Add new user data */} +
+ + Add +
+
); }; diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 568783c..8b91afc 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -32,9 +32,7 @@ const GlobalProperties: React.FC = () => { const { renderDistance, setRenderDistance } = useRenderDistance(); const { setPlaneValue, setGridValue, planeValue, gridValue } = useTileDistance(); - useEffect(() => { - - }, [gridValue, planeValue]); + useEffect(() => {}, [gridValue, planeValue]); const { socket } = useSocketStore(); const { limitDistance, setLimitDistance } = useLimitDistance(); const [distance, setDistance] = useState(40); @@ -224,66 +222,66 @@ const GlobalProperties: React.FC = () => { // } return (
-
Environment
-
- - Optimize -
+
+
Environment
+
+ + Optimize +
-
+
- - - - + + + + -
- {/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */} - { - // setLimitDistance(!limitDistance); - // // setDistance(75); - // // setRenderDistance(75); - // }} - onClick={async () => { - await limitRenderDistance(); // Call the function here - }} - /> - updateDistance(value)} - onPointerUp={updatedDist} - key={"6"} - /> - -
+
+ {/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */} + { + // setLimitDistance(!limitDistance); + // // setDistance(75); + // // setRenderDistance(75); + // }} + onClick={async () => { + await limitRenderDistance(); // Call the function here + }} + /> + updateDistance(value)} + onPointerUp={updatedDist} + key={"6"} + /> + {/*
{ max={5} onChange={(value: number) => updateGridDistance(value)} onPointerUp={updatedGrid} - /> + /> */} +
); }; diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index a9f8cc0..1bb9400 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -2,7 +2,12 @@ import React, { useEffect, useState } from "react"; import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore"; -import { useEditPosition, usezonePosition, useZones, usezoneTarget } from "../../../../store/store"; +import { + useEditPosition, + usezonePosition, + useZones, + usezoneTarget, +} from "../../../../store/store"; import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation"; const ZoneProperties: React.FC = () => { @@ -13,9 +18,9 @@ const ZoneProperties: React.FC = () => { const { zones, setZones } = useZones(); useEffect(() => { - setZonePosition(selectedZone.zoneViewPortPosition) - setZoneTarget(selectedZone.zoneViewPortTarget) - }, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget]) + setZonePosition(selectedZone.zoneViewPortPosition); + setZoneTarget(selectedZone.zoneViewPortTarget); + }, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget]); async function handleSetView() { try { @@ -25,7 +30,7 @@ const ZoneProperties: React.FC = () => { let zonesdata = { zoneId: selectedZone.zoneId, viewPortposition: zonePosition, - viewPortCenter: zoneTarget + viewPortCenter: zoneTarget, }; let response = await zoneCameraUpdate(zonesdata, organization); @@ -34,14 +39,11 @@ const ZoneProperties: React.FC = () => { } else { // console.log(response); } - - } catch (error) { - - } + } catch (error) {} } function handleEditView() { - setEdit(!Edit); // This will toggle the `Edit` state correctly + setEdit(!Edit); // This will toggle the `Edit` state correctly } async function handleZoneNameChange(newName: string) { @@ -49,11 +51,11 @@ const ZoneProperties: React.FC = () => { const organization = email?.split("@")[1]?.split(".")[0]; const zonesdata = { zoneId: selectedZone.zoneId, - zoneName: newName + zoneName: newName, }; // Call your API to update the zone let response = await zoneCameraUpdate(zonesdata, organization); - console.log('response: ', response); + console.log("response: ", response); if (response.message === "updated successfully") { setZones((prevZones: any[]) => prevZones.map((zone) => @@ -66,7 +68,10 @@ const ZoneProperties: React.FC = () => { // console.log(response?.message); } } - function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) { + function handleVectorChange( + key: "zoneViewPortTarget" | "zoneViewPortPosition", + newValue: [number, number, number] + ) { setSelectedZone((prev) => ({ ...prev, [key]: newValue })); } const checkZoneNameDuplicate = (name: string) => { @@ -79,33 +84,40 @@ const ZoneProperties: React.FC = () => { return (
-
- -
- {Edit ? "Cancel" : "Edit"} +
+
+ +
+ {Edit ? "Cancel" : "Edit"} +
-
- handleVectorChange("zoneViewPortTarget", value)} - header="Viewport Target" - value={zoneTarget as [number, number, number]} - disabled={!Edit} - /> - handleVectorChange("zoneViewPortPosition", value)} - header="Viewport Position" - value={zonePosition as [number, number, number]} - disabled={!Edit} - /> + handleVectorChange("zoneViewPortTarget", value)} + header="Viewport Target" + value={zoneTarget as [number, number, number]} + disabled={!Edit} + /> + + handleVectorChange("zoneViewPortPosition", value) + } + header="Viewport Position" + value={zonePosition as [number, number, number]} + disabled={!Edit} + /> - {Edit && ( -
- Set View -
- )} + {Edit && ( +
+ Set View +
+ )} +
); }; export default ZoneProperties; - diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 847d035..88ae240 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import { + useSelectedAsset, useSelectedEventData, useSelectedEventSphere, useSelectedProduct, @@ -11,6 +12,7 @@ import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; const EventProperties: React.FC = () => { const { selectedEventData } = useSelectedEventData(); @@ -20,8 +22,10 @@ const EventProperties: React.FC = () => { null ); const [assetType, setAssetType] = useState(null); - const { products } = useProductStore(); + const { products, addEvent } = useProductStore(); const { selectedEventSphere } = useSelectedEventSphere(); + + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); useEffect(() => { const event = getCurrentEventData(); setCurrentEventData(event); @@ -77,7 +81,7 @@ const EventProperties: React.FC = () => { )} {!currentEventData && selectedEventSphere && ( -
+

Oops! It looks like this object doesn't have an event assigned yet. To continue, please link it to one of the @@ -91,7 +95,19 @@ const EventProperties: React.FC = () => {

    {products.map((product) => (
  • - @@ -102,7 +118,7 @@ const EventProperties: React.FC = () => {
)} {!selectedEventSphere && ( -
+

Oops! It looks like you haven't selected an event point yet. Please select an event to view its properties. diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index b370b3e..7a0bc07 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -135,7 +135,7 @@ function ConveyorMechanics() { <> {selectedEventData && ( <> -

+
+
+ - - -
-
- +
+
+ +
+
+ + {activeOption === "default" && } + {activeOption === "spawn" && ( + + )} + {activeOption === "swap" && ( + + )} + {activeOption === "despawn" && } + {activeOption === "delay" && ( + + )} +
-
- - {activeOption === "default" && } - {activeOption === "spawn" && ( - - )} - {activeOption === "swap" && ( - - )} - {activeOption === "despawn" && } - {activeOption === "delay" && ( - - )} +
+
-
-
- -
+
)} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index fa2cfdf..db785da 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -85,7 +85,7 @@ function MachineMechanics() { return ( <> {selectedEventData && ( - <> +
- +
)} ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 7c20ce5..acf65ae 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -134,7 +134,7 @@ function RoboticArmMechanics() { <> {selectedEventData && selectedPointData && ( <> -
+
+
+ - - - {selectedAction.actionId && currentAction && ( -
-
- + {selectedAction.actionId && currentAction && ( +
+
+ +
+
+ {}} + disabled={true} + /> + +
+
+ +
-
- {}} - disabled={true} - /> - -
-
- -
-
- )} + )} +
)} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index d92ed80..ae7a498 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -74,7 +74,7 @@ function StorageMechanics() { return ( <> {selectedEventData && ( - <> +
- + )} ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 4524ceb..d8456e5 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -75,18 +75,10 @@ function VehicleMechanics() { const handlePickPointChange = (value: string) => { if (!selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); - updateAction(selectedPointData.action.actionUuid, { - pickUpPoint: { x, y, z }, - }); }; const handleUnloadPointChange = (value: string) => { if (!selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); - updateAction(selectedPointData.action.actionUuid, { - unLoadPoint: { x, y, z }, - }); }; // Get current values from store @@ -107,13 +99,9 @@ function VehicleMechanics() { ? selectedPointData.action.unLoadDuration.toString() : "1"; - const currentPickPoint = selectedPointData?.action.pickUpPoint - ? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}` - : ""; + const currentPickPoint = selectedPointData?.action.pickUpPoint; - const currentUnloadPoint = selectedPointData?.action.unLoadPoint - ? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}` - : ""; + const currentUnloadPoint = selectedPointData?.action.unLoadPoint; const availableActions = { defaultOption: "travel", @@ -124,7 +112,7 @@ function VehicleMechanics() { <> {selectedEventData && ( <> -
+
- -
-
- -
-
- - - {activeOption === "travel" && ( - + +
+
+ - )} +
+
+ + + {activeOption === "travel" && ( + + )} +
-
-
- -
+
+ +
+ )} diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 926ce44..a8957d1 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -1,204 +1,220 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { - AddIcon, - ArrowIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + ArrowIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; -import { useSelectedAsset, useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { + useSelectedAsset, + useSelectedProduct, +} from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { generateUUID } from "three/src/math/MathUtils"; import RenderOverlay from "../../../templates/Overlay"; import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; +import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; interface Event { - pathName: string; + pathName: string; } interface ListProps { - val: Event; + val: Event; } const List: React.FC = ({ val }) => { - return ( -
-
- {val.pathName} -
-
- ); + return ( +
+
{val.pathName}
+
+ ); }; const Simulations: React.FC = () => { - const productsContainerRef = useRef(null); - const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent } = useProductStore(); - const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); + const productsContainerRef = useRef(null); + const { + products, + addProduct, + removeProduct, + renameProduct, + addEvent, + removeEvent, + } = useProductStore(); + const { selectedProduct, setSelectedProduct } = useSelectedProduct(); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); - const handleAddProduct = () => { - addProduct(`Product ${products.length + 1}`, generateUUID()); - }; + const [openObjects, setOpenObjects] = useState(true); - const handleRemoveProduct = (productId: string) => { - const currentIndex = products.findIndex(p => p.productId === productId); - const isSelected = selectedProduct.productId === productId; + const handleAddProduct = () => { + addProduct(`Product ${products.length + 1}`, generateUUID()); + }; - const updatedProducts = products.filter(p => p.productId !== productId); + const handleRemoveProduct = (productId: string) => { + const currentIndex = products.findIndex((p) => p.productId === productId); + const isSelected = selectedProduct.productId === productId; - if (isSelected) { - if (updatedProducts.length > 0) { - let newSelectedIndex = currentIndex; - if (currentIndex >= updatedProducts.length) { - newSelectedIndex = updatedProducts.length - 1; - } - setSelectedProduct( - updatedProducts[newSelectedIndex].productId, - updatedProducts[newSelectedIndex].productName - ); - } else { - setSelectedProduct('', ''); - } + const updatedProducts = products.filter((p) => p.productId !== productId); + + if (isSelected) { + if (updatedProducts.length > 0) { + let newSelectedIndex = currentIndex; + if (currentIndex >= updatedProducts.length) { + newSelectedIndex = updatedProducts.length - 1; } + setSelectedProduct( + updatedProducts[newSelectedIndex].productId, + updatedProducts[newSelectedIndex].productName + ); + } else { + setSelectedProduct("", ""); + } + } - removeProduct(productId); - }; + removeProduct(productId); + }; - const handleRenameProduct = (productId: string, newName: string) => { - renameProduct(productId, newName); - if (selectedProduct.productId === productId) { - setSelectedProduct(productId, newName); - } - }; + const handleRenameProduct = (productId: string, newName: string) => { + renameProduct(productId, newName); + if (selectedProduct.productId === productId) { + setSelectedProduct(productId, newName); + } + }; - const handleAddEventToProduct = () => { - if (selectedAsset) { - addEvent(selectedProduct.productId, selectedAsset); - // upsertProductOrEventApi({ - // productName: selectedProduct.productName, - // productId: selectedProduct.productId, - // eventDatas: selectedAsset - // }); - clearSelectedAsset(); - } - }; + const handleRemoveEventFromProduct = () => { + if (selectedAsset) { + removeEvent(selectedProduct.productId, selectedAsset.modelUuid); + clearSelectedAsset(); + } + }; - const handleRemoveEventFromProduct = () => { - if (selectedAsset) { - removeEvent(selectedProduct.productId, selectedAsset.modelUuid); - clearSelectedAsset(); - } - }; + const selectedProductData = products.find( + (product) => product.productId === selectedProduct.productId + ); - const selectedProductData = products.find( - (product) => product.productId === selectedProduct.productId - ); - - const events: Event[] = selectedProductData?.eventDatas.map((event) => ({ - pathName: event.modelName, + const events: Event[] = + selectedProductData?.eventDatas.map((event) => ({ + pathName: event.modelName, })) || []; - return ( -
-
Simulations
-
-
-
-
Products
-
- Add -
-
-
-
- {products.map((product, index) => ( -
-
setSelectedProduct(product.productId, product.productName)} - > - - handleRenameProduct(product.productId, newName)} - /> -
- {products.length > 1 && ( -
handleRemoveProduct(product.productId)} - > - -
- )} -
- ))} -
-
handleResize(e, productsContainerRef)} - > - -
-
-
- -
-
-
Events
-
- -
-
- {events.map((event, index) => ( - - ))} -
- -
-
- Need to Compare Layout? -
-
- Click 'Compare' to review and analyze the layout differences between them. -
-
- -
-
+ return ( +
+
Simulations
+
+
+
+
Products
+
+ Add
- - {selectedAsset && - - { - if (option === 'Add to Product') { - handleAddEventToProduct(); - } else { - handleRemoveEventFromProduct(); - } - }} +
+
+
+ {products.map((product, index) => ( +
+
+ setSelectedProduct(product.productId, product.productName) + } + > + - - } + + handleRenameProduct(product.productId, newName) + } + /> +
+ {products.length > 1 && ( +
handleRemoveProduct(product.productId)} + > + +
+ )} +
+ ))} +
+
handleResize(e, productsContainerRef)} + > + +
+
- ); + +
+ + {openObjects && + events.map((event, index) => )} +
+ +
+
+ Need to Compare Layout? +
+
+ Click 'Compare' to review and analyze the layout + differences between them. +
+
+ +
+
+
+ + {selectedAsset && ( + + { + if (option === "Add to Product") { + handleAddEventToProduct({ + selectedAsset, + addEvent, + selectedProduct, + clearSelectedAsset, + }); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + )} +
+ ); }; export default Simulations; diff --git a/app/src/components/templates/FollowPerson.tsx b/app/src/components/templates/FollowPerson.tsx new file mode 100644 index 0000000..a85d0c9 --- /dev/null +++ b/app/src/components/templates/FollowPerson.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import RenderOverlay from "./Overlay"; +import { useSelectedUserStore } from "../../store/useCollabStore"; +import { useCamMode } from "../../store/store"; + +const FollowPerson: React.FC = () => { + // Get the selected user from the store + const { selectedUser, clearSelectedUser } = useSelectedUserStore(); + const { setCamMode } = useCamMode(); + return ( + + {selectedUser && ( + // eslint-disable-next-line +
{ + clearSelectedUser(); + setCamMode("FirstPerson"); + }} + style={{ "--user-color": selectedUser.color } as React.CSSProperties} + > +
{selectedUser.name}
+
+ )} +
+ ); +}; + +export default FollowPerson; diff --git a/app/src/components/ui/FileMenu.tsx b/app/src/components/ui/FileMenu.tsx index a7c876d..da85e54 100644 --- a/app/src/components/ui/FileMenu.tsx +++ b/app/src/components/ui/FileMenu.tsx @@ -1,25 +1,53 @@ -import React, { useState } from "react"; +import React, { useState, useEffect, useRef } from "react"; import RenameInput from "./inputs/RenameInput"; import { ArrowIcon } from "../icons/ExportCommonIcons"; import MenuBar from "./menu/menu"; +import { ProjectIcon } from "../icons/HeaderIcons"; const FileMenu: React.FC = () => { const [openMenu, setOpenMenu] = useState(false); + const containerRef = useRef(null); + let clickTimeout: NodeJS.Timeout | null = null; + + const handleClick = () => { + if (clickTimeout) return; + setOpenMenu((prev) => !prev); + clickTimeout = setTimeout(() => { + clickTimeout = null; + }, 800); + }; + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + containerRef.current && + !containerRef.current.contains(event.target as Node) + ) { + setOpenMenu(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + return ( -
+ ); }; diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx new file mode 100644 index 0000000..192e009 --- /dev/null +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -0,0 +1,68 @@ +import React, { useState } from "react"; +import { ProductionCapacityIcon } from "../../icons/analysis"; + +const ProductionCapacity = ({ + progressPercent = 10, + avgProcessTime = "28.4 Secs/unit", + machineUtilization = "78%", + throughputValue = 128, + timeRange = { startTime: "08:00 AM", endTime: "09:00 AM" }, +}) => { + const totalBars = 6; + const barsToFill = Math.floor((progressPercent / 100) * totalBars); + const partialFillPercent = + ((progressPercent / 100) * totalBars - barsToFill) * 100; + + return ( +
+
+
+
+
Production Capacity
+
+ {timeRange.startTime} - {timeRange.endTime} +
+
+
+ +
+
+ +
+
+ {throughputValue} Units/hour +
+ + {/* Dynamic Progress Bar */} +
+ {[...Array(totalBars)].map((_, i) => ( +
+ {i < barsToFill ? ( +
+ ) : i === barsToFill ? ( +
+ ) : null} +
+ ))} +
+
+ +
+
+ Avg. Process Time + {avgProcessTime} +
+
+ Machine Utilization + {machineUtilization} +
+
+
+
+ ); +}; + +export default ProductionCapacity; diff --git a/app/src/components/ui/analysis/ROISummary.tsx b/app/src/components/ui/analysis/ROISummary.tsx new file mode 100644 index 0000000..11101fd --- /dev/null +++ b/app/src/components/ui/analysis/ROISummary.tsx @@ -0,0 +1,188 @@ +import React, { useState } from "react"; +import { ROISummaryIcon } from "../../icons/analysis"; +import SemiCircleProgress from "./SemiCircleProgress"; + +const ROISummary = ({ + roiSummaryData = { + productName: "Product name", + roiPercentage: 133, + paybackPeriod: 50.3, + totalCost: "₹ 1,20,000", + revenueGenerated: "₹ 2,80,000", + netProfit: "₹ 1,60,000", + costBreakdown: [ + { + item: "Raw Material A", + unitCost: "₹ 10/unit", + laborCost: "₹ 0", + totalCost: "₹ 1000", + sellingPrice: "₹ 1500", + }, + { + item: "Labor", + unitCost: "₹ 10/unit", + laborCost: "₹ 500", + totalCost: "₹ 500", + sellingPrice: "N/A", + }, + { + item: "Product 1", + unitCost: "₹ 10/unit", + laborCost: "₹ 200", + totalCost: "₹ 200", + sellingPrice: "₹ 2000", + }, + { + item: "Machine", + unitCost: "-", + laborCost: "-", + totalCost: "₹ 20,000", + sellingPrice: "N/A", + }, + { + item: "Total", + unitCost: "-", + laborCost: "-", + totalCost: "₹ 1,20,000", + sellingPrice: "-", + }, + { + item: "Net Profit", + unitCost: "-", + laborCost: "-", + totalCost: "₹ 1,60,000", + sellingPrice: "-", + }, + ], + }, +}) => { + const [isTableOpen, setIsTableOpen] = useState(false); // State to handle the table open/close + + // Function to toggle the breakdown table visibility + const toggleTable = () => { + setIsTableOpen(!isTableOpen); + }; + + return ( +
+
+
+
+
ROI Summary
+
From 24 November, 2025
+
+
+ +
+
+
+
Product :
+
{roiSummaryData.productName}
+
+
+
+
+ +{roiSummaryData.roiPercentage}% ROI with payback in + just {roiSummaryData.paybackPeriod} months +
+
+
+
+ +
+ you're on track to hit it by +
July 2029
+
+
+
+
+
+ Total Cost Incurred + {roiSummaryData.totalCost} +
+
+ Revenue Generated + + {roiSummaryData.revenueGenerated} + +
+
+
+ Net Profit + {roiSummaryData.netProfit} +
+
+
+
+
+
+ â‘  + Cost Breakdown +
+ + + {isTableOpen ? "⌵" : "⌵"} + +
+
+ + + + + + + + + + + + {roiSummaryData.costBreakdown.map((row, index) => ( + + + + + + + + ))} + +
ItemUnit CostLabor CostTotal CostSelling Price
{row.item}{row.unitCost}{row.laborCost}{row.totalCost}{row.sellingPrice}
+
+
+
+
+ 💡 + How to improve ROI? +
+
+ Increase CNC utilization by 10%{" "} + to shave 0.5 months of payback + period +
+ +
+
+
+ ); +}; + +export default ROISummary; diff --git a/app/src/components/ui/analysis/SemiCircleProgress.tsx b/app/src/components/ui/analysis/SemiCircleProgress.tsx new file mode 100644 index 0000000..084636b --- /dev/null +++ b/app/src/components/ui/analysis/SemiCircleProgress.tsx @@ -0,0 +1,27 @@ +import React from "react"; + +const SemiCircleProgress = () => { + const progress = 50; + const clampedProgress = Math.min(Math.max(progress, 0), 100); + const gradientProgress = clampedProgress * 0.5; + + return ( +
+
+
+
+
+
{clampedProgress}%
+
Years
+
+
you're on track to hit it by July 2029
+
+ ); +}; + +export default SemiCircleProgress; diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx new file mode 100644 index 0000000..b92a82d --- /dev/null +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -0,0 +1,177 @@ +import React from "react"; +import { Line } from "react-chartjs-2"; +import { + Chart as ChartJS, + LineElement, + CategoryScale, + LinearScale, + PointElement, +} from "chart.js"; +import { PowerIcon, ThroughputSummaryIcon } from "../../icons/analysis"; + +ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); + +// Helper function to generate random colors +const getRandomColor = () => { + const letters = "0123456789ABCDEF"; + let color = "#"; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +}; + +const ThroughputSummary = () => { + // Define all data internally within the component + const timeRange = { + startTime: "08:00 AM", + endTime: "09:00 AM", + }; + + const throughputData = { + labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50", "09:00"], + data: [100, 120, 110, 130, 125, 128, 132], + totalThroughput: 1240, + assetUsage: 85, + }; + + const energyConsumption = { + energyConsumed: 456, + unit: "KWH", + }; + + // Dynamic shift data + const shiftUtilization = [ + { shift: 1, percentage: 30 }, + { shift: 2, percentage: 40 }, + { shift: 3, percentage: 30 }, + ]; + + // Chart data configuration + const chartData = { + labels: throughputData.labels, + datasets: [ + { + label: "Units/hour", + data: throughputData.data, + borderColor: "#B392F0", + tension: 0.4, + pointRadius: 0, // Hide points + }, + ], + }; + + const chartOptions = { + responsive: true, + scales: { + x: { + grid: { + display: false, + }, + ticks: { + display: false, + color: "#fff", + }, + }, + y: { + grid: { + display: false, + }, + ticks: { + display: false, + color: "#fff", + }, + }, + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + enabled: true, + }, + }, + }; + + return ( +
+
+
+
+
Throughput Summary
+
+ {timeRange.startTime} - {timeRange.endTime} +
+
+
+ +
+
+ +
+
+ {throughputData.totalThroughput}{" "} + Units/hour +
+
+
+
Asset usage
+
{throughputData.assetUsage}%
+
+ +
+
+ +
+
+
Energy Consumption
+
+
+ +
+
+
{energyConsumption.energyConsumed}
+
{energyConsumption.unit}
+
+
+
+
+
Shift Utilization
+
+
{throughputData.assetUsage}%
+ +
+ {/* Dynamically create progress bars based on shiftUtilization array */} + {shiftUtilization.map((shift) => ( +
+ ))} +
+ +
+ {/* Dynamically create shift indicators with random colors */} + {shiftUtilization.map((shift) => ( +
+ + +
+ ))} +
+
+
+
+
+
+ ); +}; + +export default ThroughputSummary; diff --git a/app/src/components/ui/inputs/InputToggle.tsx b/app/src/components/ui/inputs/InputToggle.tsx index 941d486..5e69291 100644 --- a/app/src/components/ui/inputs/InputToggle.tsx +++ b/app/src/components/ui/inputs/InputToggle.tsx @@ -24,11 +24,16 @@ const InputToggle: React.FC = ({ -
+
diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 528fbc2..5313710 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -7,6 +7,15 @@ import { usePlayButtonStore, useResetButtonStore, } from "../../../store/usePlayButtonStore"; +import { + DailyProductionIcon, + EndIcon, + ExpandIcon, + HourlySimulationIcon, + MonthlyROI, + SpeedIcon, + StartIcon, +} from "../../icons/ExportCommonIcons"; const SimulationPlayer: React.FC = () => { const { speed, setSpeed } = useAnimationPlaySpeed(); @@ -30,7 +39,7 @@ const SimulationPlayer: React.FC = () => { const handleExit = () => { setPlaySimulation(false); setIsPlaying(false); - setActiveTool("cursor") + setActiveTool("cursor"); }; // Slider functions starts @@ -72,70 +81,277 @@ const SimulationPlayer: React.FC = () => { }, []); // Slider function ends + // UI-Part + const hourlySimulation = 25; + const dailyProduction = 75; + const monthlyROI = 50; + + const process = [ + { name: "process 1", completed: 0 }, // 0% completed + { name: "process 2", completed: 20 }, // 20% completed + { name: "process 3", completed: 40 }, // 40% completed + { name: "process 4", completed: 60 }, // 60% completed + { name: "process 5", completed: 80 }, // 80% completed + { name: "process 6", completed: 100 }, // 100% completed + { name: "process 7", completed: 0 }, // 0% completed + { name: "process 8", completed: 50 }, // 50% completed + { name: "process 9", completed: 90 }, // 90% completed + { name: "process 10", completed: 30 }, // 30% completed + ]; + const [expand, setExpand] = useState(false); + // Move getRandomColor out of render + const getRandomColor = () => { + const letters = "0123456789ABCDEF"; + let color = "#"; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + }; + + // Store colors for each process item + const [processColors, setProcessColors] = useState([]); + + // Generate colors on mount or when process changes + useEffect(() => { + const generatedColors = process.map(() => getRandomColor()); + setProcessColors(generatedColors); + }, []); + + const intervals = [10, 20, 30, 40, 50, 60]; // in minutes + const totalSegments = intervals.length; + const progress = 80; // percent (example) + + const processPlayerRef = useRef(null); + const processWrapperRef = useRef(null); + const [playerPosition, setPlayerPosition] = useState(0); + + const handleProcessMouseDown = (e: React.MouseEvent) => { + if (!processWrapperRef.current) return; + + const rect = processWrapperRef.current.getBoundingClientRect(); + let x = e.clientX - rect.left; + x = Math.max(0, Math.min(x, rect.width)); + setPlayerPosition(x); + + const onMouseMove = (e: MouseEvent) => { + if (!processWrapperRef.current) return; + const newRect = processWrapperRef.current.getBoundingClientRect(); + let newX = e.clientX - newRect.left; + newX = Math.max(0, Math.min(newX, newRect.width)); + setPlayerPosition(newX); + + const progressPercent = (newX / newRect.width) * 100; + console.log(`Dragging at progress: ${progressPercent.toFixed(1)}%`); + }; + + const onMouseUp = () => { + document.removeEventListener("mousemove", onMouseMove); + document.removeEventListener("mouseup", onMouseUp); + }; + + document.addEventListener("mousemove", onMouseMove); + document.addEventListener("mouseup", onMouseUp); + }; + return (
-
+
-
{ - handleReset(); - }} - > - - Reset -
-
{ - handlePlayStop(); - }} - > - - {playSimulation ? "Play" : "Stop"} -
-
{ - handleExit(); - }} - > - - Exit -
-
-
-
0.5x
-
-
-
-
-
-
-
-
-
-
-
-
- {speed.toFixed(1)}x +
+ {/* hourlySimulation */} +
+
+
+ +
+
Hourly Simulation
- +
+
+
+
+ {/* dailyProduction */} +
+
+
+ +
+
Daily Production
+
+
+
+
+
+ {/* monthlyROI */} +
+
+
+ +
+
Monthly ROI
+
+
+
+
{" "}
-
8x
+
+
{ + handleReset(); + }} + > + + Reset +
+
{ + handlePlayStop(); + }} + > + + {playSimulation ? "Play" : "Stop"} +
+
{ + handleExit(); + }} + > + + Exit +
+
setExpand(!expand)} + > + +
+
+
+
+
+
+
+ +
+
+
23 April ,25
+
04:41 PM
+
+
+
+
+ {intervals.map((label, index) => { + const segmentProgress = (index / totalSegments) * 100; + const isFilled = progress >= segmentProgress; + return ( + +
+
{label} mins
+
+
+ {index < intervals.length - 1 && ( +
= ((index + 1) / totalSegments) * 100 + ? "filled" + : "" + }`} + >
+ )} +
+ ); + })} +
+
+ +
+
+
00:10:20
+
+
+ +
+
+
+
+
+
+ +
+ Speed +
+
+
0X
+
+
+
+
+
+
+
+
+
+
+
+ {speed.toFixed(1)}x +
+ +
+
8x
+
+
+
+
+
+
+ {process.map((item, index) => ( +
+ ))} +
+
diff --git a/app/src/functions/collabUserIcon.tsx b/app/src/functions/collabUserIcon.tsx deleted file mode 100644 index 9e6802b..0000000 --- a/app/src/functions/collabUserIcon.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; -import CustomAvatar from "./users/Avatar"; - -interface CollabUserIconProps { - userName: string; - userImage?: string; - color: string; -} - -const CollabUserIcon: React.FC = ({ - userImage, - userName, - color, -}) => { - return ( -
-
- {userImage ? ( - {userName} - ) : ( - - )} -
-
- {userName} -
-
- ); -}; - -export default CollabUserIcon; diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index e5ff1c1..d367493 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -18,20 +18,20 @@ import Window from "../../assets/gltf-glb/window.glb"; ////////// Zustand State Imports ////////// import { - useToggleView, - useDeletePointOrLine, - useMovePoint, - useActiveLayer, - useSocketStore, - useWallVisibility, - useRoofVisibility, - useShadows, - useUpdateScene, - useWalls, - useToolMode, - useRefTextUpdate, - useRenderDistance, - useLimitDistance, + useToggleView, + useDeletePointOrLine, + useMovePoint, + useActiveLayer, + useSocketStore, + useWallVisibility, + useRoofVisibility, + useShadows, + useUpdateScene, + useWalls, + useToolMode, + useRefTextUpdate, + useRenderDistance, + useLimitDistance, } from "../../store/store"; ////////// 3D Function Imports ////////// @@ -56,300 +56,301 @@ import ZoneGroup from "./groups/zoneGroup"; import useModuleStore from "../../store/useModuleStore"; import MeasurementTool from "../scene/tools/measurementTool"; import NavMesh from "../simulation/vehicle/navMesh/navMesh"; +import ProductionCapacity from "../../components/ui/analysis/ProductionCapacity"; export default function Builder() { - const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. - const csg = useRef(); // Reference for CSG object, used for 3D modeling. - const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. - const scene = useRef() as Types.RefScene; // Reference to the scene. - const camera = useRef() as Types.RefCamera; // Reference to the camera object. - const controls = useRef(); // Reference to the controls object. - const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. - const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. + const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. + const csg = useRef(); // Reference for CSG object, used for 3D modeling. + const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. + const scene = useRef() as Types.RefScene; // Reference to the scene. + const camera = useRef() as Types.RefCamera; // Reference to the camera object. + const controls = useRef(); // Reference to the controls object. + const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. + const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. - // Assigning the scene and camera from the Three.js state to the references. + // Assigning the scene and camera from the Three.js state to the references. - scene.current = state.scene; - camera.current = state.camera; - controls.current = state.controls; - raycaster.current = state.raycaster; + scene.current = state.scene; + camera.current = state.camera; + controls.current = state.controls; + raycaster.current = state.raycaster; - const plane = useRef(null); // Reference for a plane object for raycaster reference. - const grid = useRef() as any; // Reference for a grid object for raycaster reference. - const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. - const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). - const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... - const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. - const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. - const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). - const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. - const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. - const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. - const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. - const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. - const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. - const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. - const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. - const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. - const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. - const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). - const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. - const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. - const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. - const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. - const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. - const floorGroupAisle = useRef() as Types.RefGroup; - const zoneGroup = useRef() as Types.RefGroup; - const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. - const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. - const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. - const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. - const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. - const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. - const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... + const plane = useRef(null); // Reference for a plane object for raycaster reference. + const grid = useRef() as any; // Reference for a grid object for raycaster reference. + const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. + const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). + const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... + const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. + const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. + const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). + const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. + const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. + const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. + const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. + const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. + const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. + const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. + const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. + const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. + const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. + const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). + const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. + const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. + const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. + const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. + const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. + const floorGroupAisle = useRef() as Types.RefGroup; + const zoneGroup = useRef() as Types.RefGroup; + const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. + const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. + const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. + const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. + const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. + const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. + const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... - const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. + const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. - const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item. - const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. - const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D. - const { toolMode, setToolMode } = useToolMode(); - const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not. - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { socket } = useSocketStore(); - const { roofVisibility, setRoofVisibility } = useRoofVisibility(); - const { wallVisibility, setWallVisibility } = useWallVisibility(); - const { shadows, setShadows } = useShadows(); - const { renderDistance, setRenderDistance } = useRenderDistance(); - const { limitDistance, setLimitDistance } = useLimitDistance(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { walls, setWalls } = useWalls(); - const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); - const { activeModule } = useModuleStore(); + const [selectedItemsIndex, setSelectedItemsIndex] = + useState(null); // State for tracking the index of the selected item. + const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. + const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D. + const { toolMode, setToolMode } = useToolMode(); + const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not. + const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); + const { socket } = useSocketStore(); + const { roofVisibility, setRoofVisibility } = useRoofVisibility(); + const { wallVisibility, setWallVisibility } = useWallVisibility(); + const { shadows, setShadows } = useShadows(); + const { renderDistance, setRenderDistance } = useRenderDistance(); + const { limitDistance, setLimitDistance } = useLimitDistance(); + const { updateScene, setUpdateScene } = useUpdateScene(); + const { walls, setWalls } = useWalls(); + const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); + const { activeModule } = useModuleStore(); - // const loader = new GLTFLoader(); - // const dracoLoader = new DRACOLoader(); + // const loader = new GLTFLoader(); + // const dracoLoader = new DRACOLoader(); - // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); - // loader.setDRACOLoader(dracoLoader); + // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); + // loader.setDRACOLoader(dracoLoader); - ////////// Assest Configuration Values ////////// + ////////// Assest Configuration Values ////////// - const AssetConfigurations: Types.AssetConfigurations = { - arch: { - modelUrl: arch, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - door: { - modelUrl: door, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - window: { - modelUrl: Window, - scale: [0.75, 0.75, 0.75], - csgscale: [5, 3, 0.5], - csgposition: [0, 1.5, 0], - positionY: (intersectionPoint) => intersectionPoint.point.y, - type: "Free-Move", - }, - }; + const AssetConfigurations: Types.AssetConfigurations = { + arch: { + modelUrl: arch, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + positionY: () => 0, + type: "Fixed-Move", + }, + door: { + modelUrl: door, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + positionY: () => 0, + type: "Fixed-Move", + }, + window: { + modelUrl: Window, + scale: [0.75, 0.75, 0.75], + csgscale: [5, 3, 0.5], + csgposition: [0, 1.5, 0], + positionY: (intersectionPoint) => intersectionPoint.point.y, + type: "Free-Move", + }, + }; - ////////// All Toggle's ////////// + ////////// All Toggle's ////////// - useEffect(() => { - setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); - if (dragPointControls.current) { - dragPointControls.current.enabled = false; - } - if (toggleView) { - Layer2DVisibility( - activeLayer, - floorPlanGroup, - floorPlanGroupLine, - floorPlanGroupPoint, - currentLayerPoint, - dragPointControls - ); - } else { - setToolMode(null); - setDeletePointOrLine(false); - setMovePoint(false); - loadWalls(lines, setWalls); - setUpdateScene(true); - line.current = []; - } - }, [toggleView]); + useEffect(() => { + setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); + if (dragPointControls.current) { + dragPointControls.current.enabled = false; + } + if (toggleView) { + Layer2DVisibility( + activeLayer, + floorPlanGroup, + floorPlanGroupLine, + floorPlanGroupPoint, + currentLayerPoint, + dragPointControls + ); + } else { + setToolMode(null); + setDeletePointOrLine(false); + setMovePoint(false); + loadWalls(lines, setWalls); + setUpdateScene(true); + line.current = []; + } + }, [toggleView]); - useEffect(() => { - THREE.Cache.clear(); - THREE.Cache.enabled = true; - }, []); + useEffect(() => { + THREE.Cache.clear(); + THREE.Cache.enabled = true; + }, []); - useEffect(() => { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; + useEffect(() => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - async function fetchVisibility() { - const visibility = await findEnvironment( - organization, - localStorage.getItem("userId")! - ); - if (visibility) { - setRoofVisibility(visibility.roofVisibility); - setWallVisibility(visibility.wallVisibility); - setShadows(visibility.shadowVisibility); - setRenderDistance(visibility.renderDistance); - setLimitDistance(visibility.limitDistance); - } - } - fetchVisibility(); - }, []); + async function fetchVisibility() { + const visibility = await findEnvironment( + organization, + localStorage.getItem("userId")! + ); + if (visibility) { + setRoofVisibility(visibility.roofVisibility); + setWallVisibility(visibility.wallVisibility); + setShadows(visibility.shadowVisibility); + setRenderDistance(visibility.renderDistance); + setLimitDistance(visibility.limitDistance); + } + } + fetchVisibility(); + }, []); - ////////// UseFrame is Here ////////// + ////////// UseFrame is Here ////////// - useFrame(() => { - if (toolMode) { - Draw( - state, - plane, - cursorPosition, - floorPlanGroupPoint, - floorPlanGroupLine, - snappedPoint, - isSnapped, - isSnappedUUID, - line, - lines, - ispreSnapped, - floorPlanGroup, - ReferenceLineMesh, - LineCreated, - setRefTextUpdate, - Tube, - anglesnappedPoint, - isAngleSnapped, - toolMode - ); - } - }); + useFrame(() => { + if (toolMode) { + Draw( + state, + plane, + cursorPosition, + floorPlanGroupPoint, + floorPlanGroupLine, + snappedPoint, + isSnapped, + isSnappedUUID, + line, + lines, + ispreSnapped, + floorPlanGroup, + ReferenceLineMesh, + LineCreated, + setRefTextUpdate, + Tube, + anglesnappedPoint, + isAngleSnapped, + toolMode + ); + } + }); - ////////// Return ////////// + ////////// Return ////////// - return ( - <> - + return ( + <> + - + - + - + - + - + - + - + - + - + - + - - - - ); + + + ); } diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index d218534..1eadd24 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -69,7 +69,9 @@ const ZoneGroup: React.FC = () => { }, transparent: true, depthWrite: false, - }), []); + }), + [] + ); useEffect(() => { const fetchZones = async () => { @@ -148,6 +150,7 @@ const ZoneGroup: React.FC = () => { } }, [toolMode, toggleView]); + // eslint-disable-next-line react-hooks/exhaustive-deps const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; @@ -503,6 +506,15 @@ const ZoneGroup: React.FC = () => { draggedSphere, movePoint, activeLayer, + raycaster, + pointer, + controls, + plane, + setZones, + setZonePoints, + addZoneToBackend, + handleDeleteZone, + updateZoneToBackend, ]); useFrame(() => { @@ -551,6 +563,7 @@ const ZoneGroup: React.FC = () => { key={index} position={midpoint} rotation={[0, -angle, 0]} + visible={false} > { const navigate = useNavigate(); @@ -20,13 +20,14 @@ const CamModelsGroup = () => { const { socket } = useSocketStore(); const { activeModule } = useModuleStore(); + // eslint-disable-next-line react-hooks/exhaustive-deps const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); loader.setDRACOLoader(dracoLoader); const [cams, setCams] = useState([]); - const [models, setModels] = useState>({}); + const [models, setModels] = useState>({}); const dedupeCams = (cams: any[]) => { const seen = new Set(); @@ -102,6 +103,7 @@ const CamModelsGroup = () => { }); socket.on("cameraUpdateResponse", (data: any) => { + if ( !groupRef.current || socket.id === data.socketId || @@ -122,6 +124,11 @@ const CamModelsGroup = () => { data.data.rotation.y, data.data.rotation.z ), + target: new THREE.Vector3( + data.data.target.x, + data.data.target.y, + data.data.target.z + ), }, })); }); @@ -131,7 +138,7 @@ const CamModelsGroup = () => { socket.off("userDisConnectResponse"); socket.off("cameraUpdateResponse"); }; - }, [socket]); + }, [email, loader, navigate, setActiveUsers, socket]); useFrame(() => { if (!groupRef.current) return; @@ -217,9 +224,11 @@ const CamModelsGroup = () => { position={[-0.015, 0, 0.7]} > diff --git a/app/src/modules/collaboration/camera/collabUserIcon.tsx b/app/src/modules/collaboration/camera/collabUserIcon.tsx new file mode 100644 index 0000000..dcdb73b --- /dev/null +++ b/app/src/modules/collaboration/camera/collabUserIcon.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import CustomAvatar from "../users/Avatar"; +import { useSelectedUserStore } from "../../../store/useCollabStore"; +import { useCamMode } from "../../../store/store"; + +interface CollabUserIconProps { + userName: string; + userImage?: string; + color: string; + position?: { + x: number; + y: number; + z: number; + }; + rotation?: { + x: number; + y: number; + z: number; + }; +} + +const CollabUserIcon: React.FC = ({ + userImage, + userName, + color, + position, + rotation, +}) => { + const { setSelectedUser } = useSelectedUserStore(); + const { setCamMode } = useCamMode(); + return ( +
+ +
+ {userName} +
+
+ ); +}; + +export default CollabUserIcon; diff --git a/app/src/modules/collaboration/collaboration.tsx b/app/src/modules/collaboration/collaboration.tsx index 84d3ab1..8835185 100644 --- a/app/src/modules/collaboration/collaboration.tsx +++ b/app/src/modules/collaboration/collaboration.tsx @@ -1,14 +1,32 @@ -import React from 'react' -import CamModelsGroup from './camera/collabCams' +import React, { useEffect } from "react"; +import CamModelsGroup from "./camera/collabCams"; +import { useSelectedUserStore } from "../../store/useCollabStore"; +import { useThree } from "@react-three/fiber"; +import setCameraView from "./functions/setCameraView"; +import { useCamMode } from "../../store/store"; -const Collaboration = () => { - return ( - <> +const Collaboration: React.FC = () => { + const { selectedUser } = useSelectedUserStore(); + const { camMode } = useCamMode(); + const { camera, controls } = useThree(); // Access R3F camera and controls - + useEffect(() => { + if(camMode !== "FollowPerson") return; + // If a user is selected, set the camera view to their location + // and update the camera and controls accordingly + if (selectedUser?.location) { + const { position, rotation } = selectedUser.location; + setCameraView({ + controls, + camera, + position, + rotation, + username: selectedUser.name, + }); + } + }, [selectedUser, camera, controls, camMode]); - - ) -} + return ; +}; -export default Collaboration \ No newline at end of file +export default Collaboration; diff --git a/app/src/functions/users/functions/getAvatarColor.ts b/app/src/modules/collaboration/functions/getAvatarColor.ts similarity index 98% rename from app/src/functions/users/functions/getAvatarColor.ts rename to app/src/modules/collaboration/functions/getAvatarColor.ts index d9a5d37..6d34edc 100644 --- a/app/src/functions/users/functions/getAvatarColor.ts +++ b/app/src/modules/collaboration/functions/getAvatarColor.ts @@ -27,7 +27,7 @@ export function getAvatarColor(index: number, name?: string): string { const localStorageKey = "userAvatarColors"; // Check if local storage is available if (name) { - let userColors = JSON.parse(localStorage.getItem(localStorageKey) || "{}"); + let userColors = JSON.parse(localStorage.getItem(localStorageKey) ?? "{}"); // Check if the user already has an assigned color if (userColors[name]) { diff --git a/app/src/functions/users/functions/getInitials.ts b/app/src/modules/collaboration/functions/getInitials.ts similarity index 100% rename from app/src/functions/users/functions/getInitials.ts rename to app/src/modules/collaboration/functions/getInitials.ts diff --git a/app/src/modules/collaboration/functions/setCameraView.ts b/app/src/modules/collaboration/functions/setCameraView.ts new file mode 100644 index 0000000..8bae59b --- /dev/null +++ b/app/src/modules/collaboration/functions/setCameraView.ts @@ -0,0 +1,33 @@ +import * as THREE from 'three'; + +interface SetCameraViewProps { + controls: any; + camera: THREE.Camera; + position: THREE.Vector3 | { x: number; y: number; z: number }; + rotation: THREE.Euler | { x: number; y: number; z: number }; + username?: string; + target?: THREE.Vector3 | { x: number; y: number; z: number }; +} + +export default async function setCameraView({ + controls, + camera, + position, + rotation, + username, + target +}: SetCameraViewProps) { + if (!controls || !camera) return; + + // Normalize position + const newPosition = position instanceof THREE.Vector3 + ? position + : new THREE.Vector3(position.x, position.y, position.z); + + if (controls.setTarget) { + controls?.setLookAt(...newPosition.toArray(), newPosition.x, 0, newPosition.z, true); + } + + // Optionally you can log + console.log(`Camera view updated by ${username ?? 'unknown user'}`); +} diff --git a/app/src/functions/users/Avatar.tsx b/app/src/modules/collaboration/users/Avatar.tsx similarity index 87% rename from app/src/functions/users/Avatar.tsx rename to app/src/modules/collaboration/users/Avatar.tsx index d3e5dca..899ecb4 100644 --- a/app/src/functions/users/Avatar.tsx +++ b/app/src/modules/collaboration/users/Avatar.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState } from "react"; -import { getInitials } from "./functions/getInitials"; -import { getAvatarColor } from "./functions/getAvatarColor"; +import { getInitials } from "../functions/getInitials"; interface AvatarProps { name: string; // Name can be a full name or initials @@ -26,7 +25,7 @@ const CustomAvatar: React.FC = ({ const initials = getInitials(name); // Convert name to initials if needed // Draw background - ctx.fillStyle = color || "#323232"; // Use color prop or generate color based on index + ctx.fillStyle = color ?? "#323232"; // Use color prop or generate color based on index ctx.fillRect(0, 0, size, size); // Draw initials @@ -40,7 +39,7 @@ const CustomAvatar: React.FC = ({ const dataURL = canvas.toDataURL("image/png"); setImageSrc(dataURL); } - }, [name, size, textColor]); + }, [color, name, size, textColor]); if (!imageSrc) { return null; // Return null while the image is being generated diff --git a/app/src/modules/market/CardsContainer.tsx b/app/src/modules/market/CardsContainer.tsx index cdbce81..eabcbe4 100644 --- a/app/src/modules/market/CardsContainer.tsx +++ b/app/src/modules/market/CardsContainer.tsx @@ -42,31 +42,33 @@ const CardsContainer: React.FC = ({ models }) => { }; return ( -
-
Products You May Like
-
- {models.length > 0 && - models.map((assetDetail) => ( - +
+
Products You May Like
+
+ {models.length > 0 && + models.map((assetDetail) => ( + + ))} + {/* */} + {selectedCard && ( + - ))} - {/* */} - {selectedCard && ( - - )} - {/* */} + )} + {/* */} +
); diff --git a/app/src/modules/scene/camera/camMode.tsx b/app/src/modules/scene/camera/camMode.tsx index b4a59b0..d216ee1 100644 --- a/app/src/modules/scene/camera/camMode.tsx +++ b/app/src/modules/scene/camera/camMode.tsx @@ -1,90 +1,144 @@ -import { useFrame, useThree } from '@react-three/fiber'; -import React, { useEffect, useState } from 'react'; -import * as CONSTANTS from '../../../types/world/worldConstants'; -import { useCamMode, useToggleView } from '../../../store/store'; -import { useKeyboardControls } from '@react-three/drei'; -import switchToThirdPerson from './switchToThirdPerson'; -import switchToFirstPerson from './switchToFirstPerson'; -import { detectModifierKeys } from '../../../utils/shortcutkeys/detectModifierKeys'; +import { useFrame, useThree } from "@react-three/fiber"; +import React, { useEffect, useState } from "react"; +import * as CONSTANTS from "../../../types/world/worldConstants"; +import { useCamMode, useToggleView } from "../../../store/store"; +import { useKeyboardControls } from "@react-three/drei"; +import switchToThirdPerson from "./switchToThirdPerson"; +import switchToFirstPerson from "./switchToFirstPerson"; +import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys"; const CamMode: React.FC = () => { - const { camMode, setCamMode } = useCamMode(); - const [, get] = useKeyboardControls() - const [isTransitioning, setIsTransitioning] = useState(false); - const state: any = useThree(); - const { toggleView } = useToggleView(); + const { camMode, setCamMode } = useCamMode(); + const [, get] = useKeyboardControls(); + const [isTransitioning, setIsTransitioning] = useState(false); + const state: any = useThree(); + const { toggleView } = useToggleView(); + const [isShiftActive, setIsShiftActive] = useState(false); - useEffect(() => { - const handlePointerLockChange = async () => { - if (document.pointerLockElement && !toggleView) { - // console.log('Pointer is locked'); - } else { - // console.log('Pointer is unlocked'); - if (camMode === "FirstPerson" && !toggleView) { - setCamMode("ThirdPerson"); - await switchToThirdPerson(state.controls, state.camera); - } - } - }; - - document.addEventListener('pointerlockchange', handlePointerLockChange); - - return () => { - document.removeEventListener('pointerlockchange', handlePointerLockChange); - }; - }, [camMode, toggleView, setCamMode, state.controls, state.camera]); - - useEffect(() => { - const handleKeyPress = async (event: any) => { - if (!state.controls) return; - - const keyCombination = detectModifierKeys(event); - - if (keyCombination === "/" && !isTransitioning && !toggleView) { - setIsTransitioning(true); - state.controls.mouseButtons.left = CONSTANTS.controlsTransition.leftMouse; - state.controls.mouseButtons.right = CONSTANTS.controlsTransition.rightMouse; - state.controls.mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse; - state.controls.mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse; - - if (camMode === 'ThirdPerson') { - setCamMode("FirstPerson"); - await switchToFirstPerson(state.controls, state.camera); - } else if (camMode === "FirstPerson") { - setCamMode("ThirdPerson"); - await switchToThirdPerson(state.controls, state.camera); - } - - setIsTransitioning(false); - } - }; - - window.addEventListener("keydown", handleKeyPress); - return () => { - window.removeEventListener("keydown", handleKeyPress); - }; - }, [camMode, isTransitioning, toggleView, state.controls, state.camera, setCamMode]); - - useFrame(() => { - const { forward, backward, left, right } = get(); - if (!state.controls) return - if (!state.controls || camMode === "ThirdPerson" || !document.pointerLockElement) return; - - if (forward) { - state.controls.forward(CONSTANTS.firstPersonControls.forwardSpeed, true) + useEffect(() => { + const handlePointerLockChange = async () => { + if (document.pointerLockElement && !toggleView) { + // Pointer is locked + } else { + // Pointer is unlocked + if (camMode === "FirstPerson" && !toggleView) { + setCamMode("ThirdPerson"); + await switchToThirdPerson(state.controls, state.camera); } - if (backward) { - state.controls.forward(CONSTANTS.firstPersonControls.backwardSpeed, true) - } - if (left) { - state.controls.truck(CONSTANTS.firstPersonControls.leftSpeed, 0, true) - } - if (right) { - state.controls.truck(CONSTANTS.firstPersonControls.rightSpeed, 0, true) - } - }); + } + }; - return null; // This component does not render any UI + document.addEventListener("pointerlockchange", handlePointerLockChange); + + return () => { + document.removeEventListener( + "pointerlockchange", + handlePointerLockChange + ); + }; + }, [camMode, toggleView, setCamMode, state.controls, state.camera]); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Shift") { + setIsShiftActive(true); + } + }; + + const handleKeyUp = (event: KeyboardEvent) => { + if (event.key === "Shift") { + setIsShiftActive(false); + } + }; + + window.addEventListener("keydown", handleKeyDown); + window.addEventListener("keyup", handleKeyUp); + + return () => { + window.removeEventListener("keydown", handleKeyDown); + window.removeEventListener("keyup", handleKeyUp); + }; + }, []); + + useEffect(() => { + const handleKeyPress = async (event: KeyboardEvent) => { + if (!state.controls) return; + + const keyCombination = detectModifierKeys(event); + + if (keyCombination === "/" && !isTransitioning && !toggleView) { + setIsTransitioning(true); + + state.controls.mouseButtons.left = + CONSTANTS.controlsTransition.leftMouse; + state.controls.mouseButtons.right = + CONSTANTS.controlsTransition.rightMouse; + state.controls.mouseButtons.wheel = + CONSTANTS.controlsTransition.wheelMouse; + state.controls.mouseButtons.middle = + CONSTANTS.controlsTransition.middleMouse; + + if (camMode === "ThirdPerson") { + setCamMode("FirstPerson"); + await switchToFirstPerson(state.controls, state.camera); + } else if (camMode === "FirstPerson") { + setCamMode("ThirdPerson"); + await switchToThirdPerson(state.controls, state.camera); + } + + setIsTransitioning(false); + } + }; + + window.addEventListener("keydown", handleKeyPress); + return () => { + window.removeEventListener("keydown", handleKeyPress); + }; + }, [ + camMode, + isTransitioning, + toggleView, + state.controls, + state.camera, + setCamMode, + ]); + + useFrame(() => { + const { forward, backward, left, right } = get(); + if (!state.controls) return; + if (camMode === "ThirdPerson" || !document.pointerLockElement) return; + + const speedMultiplier = isShiftActive ? 4 : 1; + + if (forward) { + state.controls.forward( + CONSTANTS.firstPersonControls.forwardSpeed * speedMultiplier, + true + ); + } + if (backward) { + state.controls.forward( + CONSTANTS.firstPersonControls.backwardSpeed * speedMultiplier, + true + ); + } + if (left) { + state.controls.truck( + CONSTANTS.firstPersonControls.leftSpeed * speedMultiplier, + 0, + true + ); + } + if (right) { + state.controls.truck( + CONSTANTS.firstPersonControls.rightSpeed * speedMultiplier, + 0, + true + ); + } + }); + + return null; // This component does not render any UI }; -export default CamMode; \ No newline at end of file +export default CamMode; diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index bc2f4db..c5025dd 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -17,12 +17,11 @@ function PointsCreator() { useEffect(() => { if (selectedEventSphere) { - const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid); + const eventData = getEventByModelUuid( + selectedEventSphere.userData.modelUuid + ); if (eventData) { - setSelectedEventData( - eventData, - selectedEventSphere.userData.pointUuid - ); + setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); } else { clearSelectedEventData(); } diff --git a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts new file mode 100644 index 0000000..7943c1c --- /dev/null +++ b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts @@ -0,0 +1,28 @@ +interface HandleAddEventToProductParams { + selectedAsset: any; // Replace `any` with specific type if you have it + addEvent: (productId: string, asset: any) => void; + selectedProduct: { + productId: string; + productName: string; + // Add other fields if needed + }; + clearSelectedAsset: () => void; +} + +export const handleAddEventToProduct = ({ + selectedAsset, + addEvent, + selectedProduct, + clearSelectedAsset, +}: HandleAddEventToProductParams) => { + console.log('selectedProduct: ', selectedProduct); + if (selectedAsset) { + addEvent(selectedProduct.productId, selectedAsset); + // upsertProductOrEventApi({ + // productName: selectedProduct.productName, + // productId: selectedProduct.productId, + // eventDatas: selectedAsset + // }); + clearSelectedAsset(); + } +}; diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index fd7590e..c82b73d 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -8,7 +8,7 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t const { armBots } = useArmBotStore(); const { scene } = useThree(); const restSpeed = 0.1; - const restPosition = new THREE.Vector3(0, 2, 1.6); + const restPosition = new THREE.Vector3(0, 1, -1.6); const initialCurveRef = useRef(null); const initialStartPositionRef = useRef(null); const [initialProgress, setInitialProgress] = useState(0); @@ -22,11 +22,12 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); useEffect(() => { + setCurrentPath(path) }, [path]) useEffect(() => { - + }, [currentPath]) useFrame((_, delta) => { @@ -42,13 +43,13 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2])) ); + const next = initialProgressRef.current + delta * 0.5; if (next >= 1) { - bone.position.copy(restPosition); + // bone.position.copy(restPosition); HandleCallback(); // Call the callback when the path is completed initialProgressRef.current = 0; // Set ref to 1 when done } else { - const point = curve.getPoint(next); // Get the interpolated point from the curve bone.position.copy(point); // Update the bone position along the curve initialProgressRef.current = next; // Update progress diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 86eee6a..3fe8af1 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -16,6 +16,7 @@ interface Process { endPoint?: Vector3; speed: number; } + function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const { isPlaying } = usePlayButtonStore(); @@ -29,7 +30,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const groupRef = useRef(null); const [processes, setProcesses] = useState([]); const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] }) - const restPosition = new THREE.Vector3(0, 2, 1.6); + const restPosition = new THREE.Vector3(0, 1, -1.6); let armBotCurveRef = useRef(null) const [path, setPath] = useState<[number, number, number][]>([]); @@ -52,7 +53,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { if (isPlaying) { //Moving armBot from initial point to rest position. if (!robot?.isActive && robot?.state == "idle" && currentPhase == "init") { - + setArmBotActive(robot.modelUuid, true) setArmBotState(robot.modelUuid, "running") setCurrentPhase("init-to-rest"); @@ -62,11 +63,11 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { setPath(curve.points.map(point => [point.x, point.y, point.z])); } } - logStatus(robot.modelUuid, "Starting from init to rest") + logStatus(robot.modelUuid, "Moving armBot from initial point to rest position.") } //Waiting for trigger. else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) { - console.log("trigger"); + logStatus(robot.modelUuid, "Waiting to trigger CurrentAction") setTimeout(() => { addCurrentAction(robot.modelUuid, 'action-003'); }, 3000); @@ -84,7 +85,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } } } - logStatus(robot.modelUuid, "Starting from rest to start") + logStatus(robot.modelUuid, "Moving armBot from rest point to start position.") } else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) { setArmBotActive(robot.modelUuid, true); @@ -98,10 +99,13 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]) ); if (curve) { - setPath(curve.points.map(point => [point.x, point.y, point.z])); + setTimeout(() => { + logStatus(robot.modelUuid, "picking the object"); + setPath(curve.points.map(point => [point.x, point.y, point.z])); + }, 1500) } } - logStatus(robot.modelUuid, "Starting from start to end") + logStatus(robot.modelUuid, "Moving armBot from start point to end position.") } else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) { setArmBotActive(robot.modelUuid, true); @@ -112,10 +116,13 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition ); if (curve) { - setPath(curve.points.map(point => [point.x, point.y, point.z])); + setTimeout(() => { + logStatus(robot.modelUuid, "dropping the object"); + setPath(curve.points.map(point => [point.x, point.y, point.z])); + }, 1500) } } - logStatus(robot.modelUuid, "Starting from end to rest") + logStatus(robot.modelUuid, "Moving armBot from end point to rest position.") } } @@ -133,28 +140,28 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const HandleCallback = () => { if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") { - console.log("Callback triggered: rest"); + logStatus(robot.modelUuid, "Callback triggered: rest"); setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("rest"); setPath([]) } else if (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") { - console.log("Callback triggered: pick."); + logStatus(robot.modelUuid, "Callback triggered: pick."); setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("picking"); setPath([]) } else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") { - console.log("Callback triggered: drop."); + logStatus(robot.modelUuid, "Callback triggered: drop."); setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("dropping"); setPath([]) } else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") { - console.log("Callback triggered: rest, cycle completed."); + logStatus(robot.modelUuid, "Callback triggered: rest, cycle completed."); setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("rest"); @@ -163,12 +170,12 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } } const logStatus = (id: string, status: string) => { - console.log(id +","+ status); + // console.log(id + "," + status); + console.log( status); } return ( <> - { const draco = new DRACOLoader(); @@ -64,16 +65,16 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks); setIkSolver(solver); - const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05); + const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05) - // scene.add(groupRef.current) + // scene.add(helper) }, [gltf]); return ( <> - + { - + removeArmBot(armBotStatusSample[0].modelUuid); addArmBot('123', armBotStatusSample[0]); // addArmBot('123', armBotStatusSample[1]); @@ -153,7 +166,7 @@ function RoboticArm() { }, []); useEffect(() => { - // + }, [armBots]); return ( diff --git a/app/src/modules/simulation/ui/arm/PickDropPoints.tsx b/app/src/modules/simulation/ui/arm/PickDropPoints.tsx new file mode 100644 index 0000000..4544a46 --- /dev/null +++ b/app/src/modules/simulation/ui/arm/PickDropPoints.tsx @@ -0,0 +1,54 @@ +import React, { useRef } from "react"; +import * as THREE from "three"; +import { ThreeEvent } from "@react-three/fiber"; + +interface PickDropProps { + position: number[]; + modelUuid: string; + pointUuid: string; + actionType: "pick" | "drop"; + actionUuid: string; + gltfScene: THREE.Group; + selectedPoint: THREE.Mesh | null; + handlePointerDown: (e: ThreeEvent) => void; + isSelected: boolean; +} + +const PickDropPoints: React.FC = ({ + position, + modelUuid, + pointUuid, + actionType, + actionUuid, + gltfScene, + selectedPoint, + handlePointerDown, + isSelected, +}) => { + const groupRef = useRef(null); + + return ( + { + e.stopPropagation(); // Important to prevent event bubbling + if (!isSelected) return; + handlePointerDown(e); + }} + userData={{ modelUuid, pointUuid, actionType, actionUuid }} + > + + + ); +}; + +export default PickDropPoints; diff --git a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts new file mode 100644 index 0000000..b7e9272 --- /dev/null +++ b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts @@ -0,0 +1,131 @@ +import { useRef } from "react"; +import * as THREE from "three"; +import { ThreeEvent, useThree } from "@react-three/fiber"; + +type OnUpdateCallback = (object: THREE.Object3D) => void; + +export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { + const { camera, gl, controls, scene } = useThree(); + const activeObjRef = useRef(null); + const planeRef = useRef( + new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) + ); + const offsetRef = useRef(new THREE.Vector3()); + const initialPositionRef = useRef(new THREE.Vector3()); + + const raycaster = new THREE.Raycaster(); + const pointer = new THREE.Vector2(); + + const handlePointerDown = (e: ThreeEvent) => { + e.stopPropagation(); + + let obj: THREE.Object3D | null = e.object; + + // Traverse up until we find modelUuid in userData + while (obj && !obj.userData?.modelUuid) { + obj = obj.parent; + } + + if (!obj) return; + + // Disable orbit controls while dragging + if (controls) (controls as any).enabled = false; + + activeObjRef.current = obj; + initialPositionRef.current.copy(obj.position); + + // Get world position + const objectWorldPos = new THREE.Vector3(); + obj.getWorldPosition(objectWorldPos); + + // Set plane at the object's Y level + planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y); + + // Convert pointer to NDC + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Raycast to intersection + raycaster.setFromCamera(pointer, camera); + const intersection = new THREE.Vector3(); + raycaster.ray.intersectPlane(planeRef.current, intersection); + + // Calculate offset + offsetRef.current.copy(objectWorldPos).sub(intersection); + + // Start listening for drag + gl.domElement.addEventListener("pointermove", handlePointerMove); + gl.domElement.addEventListener("pointerup", handlePointerUp); + }; + + const handlePointerMove = (e: PointerEvent) => { + if (!activeObjRef.current) return; + + // Check if Shift key is pressed + const isShiftKeyPressed = e.shiftKey; + + // Get the mouse position relative to the canvas + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Update raycaster to point to the mouse position + raycaster.setFromCamera(pointer, camera); + + // Create a vector to store intersection point + const intersection = new THREE.Vector3(); + const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection); + if (!intersects) return; + + // Add offset for dragging + intersection.add(offsetRef.current); + console.log('intersection: ', intersection); + + // Get the parent's world matrix if exists + const parent = activeObjRef.current.parent; + const targetPosition = new THREE.Vector3(); + + if (isShiftKeyPressed) { + console.log('isShiftKeyPressed: ', isShiftKeyPressed); + // For Y-axis only movement, maintain original X and Z + console.log('initialPositionRef: ', initialPositionRef); + console.log('intersection.y: ', intersection); + targetPosition.set( + initialPositionRef.current.x, + intersection.y, + initialPositionRef.current.z + ); + } else { + // For free movement + targetPosition.copy(intersection); + } + + // Convert world position to local if object is nested inside a parent + if (parent) { + parent.worldToLocal(targetPosition); + } + + // Update object position + activeObjRef.current.position.copy(targetPosition); + }; + + const handlePointerUp = () => { + if (controls) (controls as any).enabled = true; + + if (activeObjRef.current) { + // Pass the updated position to the onUpdate callback to persist it + onUpdate(activeObjRef.current); + } + + gl.domElement.removeEventListener("pointermove", handlePointerMove); + gl.domElement.removeEventListener("pointerup", handlePointerUp); + + activeObjRef.current = null; + }; + + return { handlePointerDown }; +} + + + diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index a0eeabd..a8cfc39 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -7,166 +7,267 @@ import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; interface VehicleAnimatorProps { - path: [number, number, number][]; - handleCallBack: () => void; - currentPhase: string; - agvUuid: number; - agvDetail: any; + path: [number, number, number][]; + handleCallBack: () => void; + reset: () => void; + currentPhase: string; + agvUuid: number; + agvDetail: any; } -function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail }: VehicleAnimatorProps) { - const { decrementVehicleLoad, vehicles } = useVehicleStore(); - const { isPaused } = usePauseButtonStore(); - const { speed } = useAnimationPlaySpeed(); - const { isReset } = useResetButtonStore(); - const [restRotation, setRestingRotation] = useState(true); - const [progress, setProgress] = useState(0); - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); - const progressRef = useRef(0); - const movingForward = useRef(true); - const completedRef = useRef(false); - let startTime: number; - let pausedTime: number; - let fixedInterval: number; +function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { + const { decrementVehicleLoad, vehicles } = useVehicleStore(); + const { isPaused } = usePauseButtonStore(); + const { speed } = useAnimationPlaySpeed(); + const { isReset } = useResetButtonStore(); + const [restRotation, setRestingRotation] = useState(true); + const [progress, setProgress] = useState(0); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const { scene } = useThree(); + const progressRef = useRef(0); + const movingForward = useRef(true); + const completedRef = useRef(false); + let startTime: number; + let pausedTime: number; + let fixedInterval: number; - useEffect(() => { - if (currentPhase === 'stationed-pickup' && path.length > 0) { - setCurrentPath(path); - } else if (currentPhase === 'pickup-drop' && path.length > 0) { - setCurrentPath(path); - } else if (currentPhase === 'drop-pickup' && path.length > 0) { - setCurrentPath(path); - } - }, [currentPhase, path]); - - useEffect(() => { - setProgress(0); - completedRef.current = false; - }, [currentPath]); - - useFrame((_, delta) => { - const object = scene.getObjectByProperty('uuid', agvUuid); - if (!object || currentPath.length < 2) return; - if (isPaused) return; - - let totalDistance = 0; - const distances = []; - - for (let i = 0; i < currentPath.length - 1; i++) { - const start = new THREE.Vector3(...currentPath[i]); - const end = new THREE.Vector3(...currentPath[i + 1]); - const segmentDistance = start.distanceTo(end); - distances.push(segmentDistance); - totalDistance += segmentDistance; - } - - let coveredDistance = progressRef.current; - let accumulatedDistance = 0; - let index = 0; - - while ( - index < distances.length && - coveredDistance > accumulatedDistance + distances[index] - ) { - accumulatedDistance += distances[index]; - index++; - } - - if (index < distances.length) { - const start = new THREE.Vector3(...currentPath[index]); - const end = new THREE.Vector3(...currentPath[index + 1]); - const segmentDistance = distances[index]; - - const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); - const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - const rotationSpeed = 2.0; - const currentAngle = object.rotation.y; - - let angleDifference = targetAngle - currentAngle; - if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; - if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - - const maxRotationStep = rotationSpeed * delta; - object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - - const isAligned = Math.abs(angleDifference) < 0.01; - - if (isAligned) { - progressRef.current += delta * (speed * agvDetail.speed); - coveredDistance = progressRef.current; - - const t = (coveredDistance - accumulatedDistance) / segmentDistance; - const position = start.clone().lerp(end, t); - object.position.copy(position); - } - } - - if (progressRef.current >= totalDistance) { - if (restRotation) { - const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); - object.quaternion.slerp(targetQuaternion, delta * 2); - const angleDiff = object.quaternion.angleTo(targetQuaternion); - if (angleDiff < 0.01) { - let objectRotation = agvDetail.point.rotation - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - setRestingRotation(false); + useEffect(() => { + if (currentPhase === 'stationed-pickup' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'pickup-drop' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'drop-pickup' && path.length > 0) { + setCurrentPath(path); } - return; - } + }, [currentPhase, path]); + + useEffect(() => { + setProgress(0); + completedRef.current = false; + }, [currentPath]); + // useEffect(() => { + // console.log('isReset: ', isReset); + // if (isReset) { + // reset(); + // setCurrentPath([]); + // setProgress(0); + // completedRef.current = false; + // decrementVehicleLoad(agvDetail.modelUuid, 0) + // } + // }, [isReset]) + + // useFrame((_, delta) => { + // const object = scene.getObjectByProperty('uuid', agvUuid); + // if (!object || currentPath.length < 2) return; + // if (isPaused) return; + + // let totalDistance = 0; + // const distances = []; + + // for (let i = 0; i < currentPath.length - 1; i++) { + // const start = new THREE.Vector3(...currentPath[i]); + // const end = new THREE.Vector3(...currentPath[i + 1]); + // const segmentDistance = start.distanceTo(end); + // distances.push(segmentDistance); + // totalDistance += segmentDistance; + // } + + // let coveredDistance = progressRef.current; + // let accumulatedDistance = 0; + // let index = 0; + + // while ( + // index < distances.length && + // coveredDistance > accumulatedDistance + distances[index] + // ) { + // accumulatedDistance += distances[index]; + // index++; + // } + + // if (index < distances.length) { + // const start = new THREE.Vector3(...currentPath[index]); + // const end = new THREE.Vector3(...currentPath[index + 1]); + // const segmentDistance = distances[index]; + + // const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + // const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + // const rotationSpeed = 2.0; + // const currentAngle = object.rotation.y; + + // let angleDifference = targetAngle - currentAngle; + // if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + // if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + + // const maxRotationStep = rotationSpeed * delta; + // object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + + // const isAligned = Math.abs(angleDifference) < 0.01; + + // if (isAligned) { + // progressRef.current += delta * (speed * agvDetail.speed); + // coveredDistance = progressRef.current; + + // const t = (coveredDistance - accumulatedDistance) / segmentDistance; + // const position = start.clone().lerp(end, t); + // object.position.copy(position); + // } + // } + + // if (progressRef.current >= totalDistance) { + // if (restRotation) { + // const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + // object.quaternion.slerp(targetQuaternion, delta * 2); + // const angleDiff = object.quaternion.angleTo(targetQuaternion); + // if (angleDiff < 0.01) { + // let objectRotation = agvDetail.point.rotation + // object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + // setRestingRotation(false); + // } + // return; + // } + // } + + // if (progressRef.current >= totalDistance) { + // setRestingRotation(true); + // progressRef.current = 0; + // movingForward.current = !movingForward.current; + // setCurrentPath([]); + // handleCallBack(); + // if (currentPhase === 'pickup-drop') { + // requestAnimationFrame(firstFrame); + // } + // } + // }); + useEffect(() => { + if (isReset) { + reset(); + setCurrentPath([]); + setProgress(0); + progressRef.current = 0; + completedRef.current = false; + movingForward.current = true; + setRestingRotation(false); + decrementVehicleLoad(agvDetail.modelUuid, 0); + } + }, [isReset]); + + useFrame((_, delta) => { + // If reset is active, don't run anything in frame + if (isReset) return; + + const object = scene.getObjectByProperty('uuid', agvUuid); + if (!object || currentPath.length < 2) return; + if (isPaused) return; + + let totalDistance = 0; + const distances = []; + + for (let i = 0; i < currentPath.length - 1; i++) { + const start = new THREE.Vector3(...currentPath[i]); + const end = new THREE.Vector3(...currentPath[i + 1]); + const segmentDistance = start.distanceTo(end); + distances.push(segmentDistance); + totalDistance += segmentDistance; + } + + let coveredDistance = progressRef.current; + let accumulatedDistance = 0; + let index = 0; + + while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { + accumulatedDistance += distances[index]; + index++; + } + + if (index < distances.length) { + const start = new THREE.Vector3(...currentPath[index]); + const end = new THREE.Vector3(...currentPath[index + 1]); + const segmentDistance = distances[index]; + + const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + const currentAngle = object.rotation.y; + + let angleDifference = targetAngle - currentAngle; + if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + + const rotationSpeed = 2.0; + const maxRotationStep = rotationSpeed * delta; + const rotationStep = Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + object.rotation.y += rotationStep; + + const isAligned = Math.abs(angleDifference) < 0.01; + + if (isAligned) { + progressRef.current += delta * (speed * agvDetail.speed); + coveredDistance = progressRef.current; + + const t = (coveredDistance - accumulatedDistance) / segmentDistance; + const position = start.clone().lerp(end, t); + object.position.copy(position); + } + } + + if (progressRef.current >= totalDistance) { + if (restRotation) { + const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + object.quaternion.slerp(targetQuaternion, delta * 2); + const angleDiff = object.quaternion.angleTo(targetQuaternion); + if (angleDiff < 0.01) { + const objectRotation = agvDetail.point.rotation; + object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + setRestingRotation(false); + } + } else { + setRestingRotation(true); + progressRef.current = 0; + movingForward.current = !movingForward.current; + setCurrentPath([]); + handleCallBack(); + if (currentPhase === 'pickup-drop') { + requestAnimationFrame(firstFrame); + } + } + } + }); + + function firstFrame() { + const unLoadDuration = agvDetail.point.action.unLoadDuration; + const droppedMaterial = agvDetail.currentLoad; + fixedInterval = (unLoadDuration / droppedMaterial) * 1000; + startTime = performance.now(); + step(droppedMaterial); } - if (progressRef.current >= totalDistance) { - setRestingRotation(true); - progressRef.current = 0; - movingForward.current = !movingForward.current; - setCurrentPath([]); - handleCallBack(); - if (currentPhase === 'pickup-drop') { - requestAnimationFrame(firstFrame); - } + function step(droppedMaterial: number) { + const elapsedTime = (performance.now() - startTime) * speed; + if (elapsedTime >= fixedInterval) { + let droppedMat = droppedMaterial - 1; + decrementVehicleLoad(agvDetail.modelUuid, 1); + if (droppedMat === 0) return; + startTime = performance.now(); + requestAnimationFrame(() => step(droppedMat)); + } else { + requestAnimationFrame(() => step(droppedMaterial)); + } } - }); - function firstFrame() { - const unLoadDuration = agvDetail.point.action.unLoadDuration; - const droppedMaterial = agvDetail.currentLoad; - fixedInterval = (unLoadDuration / droppedMaterial) * 1000; - startTime = performance.now(); - step(droppedMaterial); - } - - function step(droppedMaterial: number) { - const elapsedTime = performance.now() - startTime; - - if (elapsedTime >= fixedInterval) { - console.log('fixedInterval: ', fixedInterval); - console.log('elapsedTime: ', elapsedTime); - let droppedMat = droppedMaterial - 1; - decrementVehicleLoad(agvDetail.modelUuid, 1); - if (droppedMat === 0) return; - startTime = performance.now(); - requestAnimationFrame(() => step(droppedMat)); - } else { - requestAnimationFrame(() => step(droppedMaterial)); - } - } - - return ( - <> - {currentPath.length > 0 && ( + return ( <> - - {currentPath.map((point, index) => ( - - - - - ))} + {currentPath.length > 0 && ( + <> + + {currentPath.map((point, index) => ( + + + + + ))} + + )} - )} - - ); + ); } export default VehicleAnimator; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index d0691f9..a7a41d3 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -3,121 +3,120 @@ import VehicleAnimator from '../animator/vehicleAnimator'; import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/store'; -import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; function VehicleInstance({ agvDetail }: any) { - const { navMesh } = useNavMesh(); - const { isPlaying } = usePlayButtonStore(); - const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); - const [currentPhase, setCurrentPhase] = useState('stationed'); - const [path, setPath] = useState<[number, number, number][]>([]); + const { navMesh } = useNavMesh(); + const { isPlaying, setIsPlaying } = usePlayButtonStore(); + const { isReset } = useResetButtonStore(); + const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState('stationed'); + const [path, setPath] = useState<[number, number, number][]>([]); - const computePath = useCallback( - (start: any, end: any) => { - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] - ); - } catch { - return []; - } - }, - [navMesh] - ); + const computePath = useCallback( + (start: any, end: any) => { + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + return ( + segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] + ); + } catch { + return []; + } + }, + [navMesh] + ); - function vehicleStatus(modelid: string, status: string) { - // console.log(`AGV ${modelid}: ${status}`); - } + function vehicleStatus(modelid: string, status: string) { + // console.log(`AGV ${modelid}: ${status}`); + } + function reset() { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setPath([]); + setCurrentPhase('stationed') + } - useEffect(() => { - if (isPlaying) { - if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { - const toPickupPath = computePath( - new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), - agvDetail.point.action.pickUpPoint - ); - setPath(toPickupPath); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('stationed-pickup'); - vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); - return; - } else if ( - !agvDetail.isActive && - agvDetail.state === 'idle' && - currentPhase === 'picking' - ) { - - setTimeout(() => { - incrementVehicleLoad(agvDetail.modelUuid, 2); - }, 5000); + useEffect(() => { + if (isPlaying) { + if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { + const toPickupPath = computePath( + new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), + agvDetail.point.action.pickUpPoint + ); + setPath(toPickupPath); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('stationed-pickup'); + vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); + return; + } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') { - if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { - const toDrop = computePath( - agvDetail.point.action.pickUpPoint, - agvDetail.point.action.unLoadPoint - ); - setPath(toDrop); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('pickup-drop'); - vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); + setTimeout(() => { + incrementVehicleLoad(agvDetail.modelUuid, 2); + }, 5000); + + if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { + const toDrop = computePath( + agvDetail.point.action.pickUpPoint, + agvDetail.point.action.unLoadPoint + ); + setPath(toDrop); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('pickup-drop'); + vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); + } + } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) { + const dropToPickup = computePath( + agvDetail.point.action.unLoadPoint, + agvDetail.point.action.pickUpPoint + ); + setPath(dropToPickup); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('drop-pickup'); + vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); + } } - } else if ( - !agvDetail.isActive && - agvDetail.state === 'idle' && - currentPhase === 'dropping' && - agvDetail.currentLoad === 0 - ) { - const dropToPickup = computePath( - agvDetail.point.action.unLoadPoint, - agvDetail.point.action.pickUpPoint - ); - setPath(dropToPickup); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('drop-pickup'); - vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); - } - } - }, [vehicles, currentPhase, path, isPlaying]); + }, [vehicles, currentPhase, path, isPlaying, isReset]); - function handleCallBack() { - if (currentPhase === 'stationed-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('picking'); - vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); - setPath([]); - } else if (currentPhase === 'pickup-drop') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('dropping'); - vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); - setPath([]); - } else if (currentPhase === 'drop-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('picking'); - setPath([]); - vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); + function handleCallBack() { + if (currentPhase === 'stationed-pickup') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('picking'); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); + setPath([]); + } else if (currentPhase === 'pickup-drop') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('dropping'); + vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); + setPath([]); + } else if (currentPhase === 'drop-pickup') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('picking'); + setPath([]); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); + } } - } - return ( - <> - - - ); + return ( + <> + + + ); } export default VehicleInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index f0b4d17..eaf12a3 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -28,8 +28,8 @@ function Vehicles() { actionType: "travel", unLoadDuration: 10, loadCapacity: 2, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, + pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, + unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ { triggerUuid: "trig-001", @@ -71,8 +71,8 @@ function Vehicles() { actionType: "travel", unLoadDuration: 10, loadCapacity: 2, - pickUpPoint: { x: 90, y: 0, z: 28 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, + pickUpPoint: { position: { x: 90, y: 0, z: 28 }, rotation: { x: 0, y: 0, z: 0 } }, + unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ { triggerUuid: "trig-001", @@ -95,7 +95,8 @@ function Vehicles() { ] } } - }, { + }, + { modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", modelName: "forklift", position: [98.85729337188162, 0, 38.36616546567653], @@ -113,8 +114,8 @@ function Vehicles() { actionType: "travel", unLoadDuration: 15, loadCapacity: 5, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, + pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, + unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ { triggerUuid: "trig-001", @@ -148,7 +149,7 @@ function Vehicles() { }, []) useEffect(() => { - console.log('vehicles: ', vehicles); + // console.log('vehicles: ', vehicles); }, [vehicles]) diff --git a/app/src/modules/visualization/widgets/panel/AddButtons.tsx b/app/src/modules/visualization/widgets/panel/AddButtons.tsx index d066cd4..4877824 100644 --- a/app/src/modules/visualization/widgets/panel/AddButtons.tsx +++ b/app/src/modules/visualization/widgets/panel/AddButtons.tsx @@ -304,8 +304,8 @@ const AddButtons: React.FC = ({
@@ -341,8 +341,8 @@ const AddButtons: React.FC = ({
diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 2daa091..c491583 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -1,11 +1,10 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import ModuleToggle from "../components/ui/ModuleToggle"; import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft"; import SideBarRight from "../components/layout/sidebarRight/SideBarRight"; import useModuleStore, { useThreeDStore } from "../store/useModuleStore"; import RealTimeVisulization from "../modules/visualization/RealTimeVisulization"; import Tools from "../components/ui/Tools"; -// import Scene from "../modules/scene/scene"; import { useSocketStore, useFloorItems, @@ -20,9 +19,9 @@ import { usePlayButtonStore } from "../store/usePlayButtonStore"; import MarketPlace from "../modules/market/MarketPlace"; import LoadingPage from "../components/templates/LoadingPage"; import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; -import RenderOverlay from "../components/templates/Overlay"; -import MenuBar from "../components/ui/menu/menu"; import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys"; +import { useSelectedUserStore } from "../store/useCollabStore"; +import FollowPerson from "../components/templates/FollowPerson"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -38,10 +37,10 @@ const Project: React.FC = () => { setFloorItems([]); setWallItems([]); setZones([]); - setActiveModule('builder') + setActiveModule("builder"); const email = localStorage.getItem("email"); if (email) { - const Organization = email!.split("@")[1].split(".")[0]; + const Organization = email.split("@")[1].split(".")[0]; useSocketStore.getState().initializeSocket(email, Organization); const name = localStorage.getItem("userName"); if (Organization && name) { @@ -52,13 +51,20 @@ const Project: React.FC = () => { navigate("/"); } }, []); + const { isPlaying } = usePlayButtonStore(); const { toggleThreeD } = useThreeDStore(); + const { selectedUser } = useSelectedUserStore(); return (
+ {/*
+ + + +
*/} - {loadingProgress && } + {loadingProgress > 0 && } {!isPlaying && ( <> {toggleThreeD && } @@ -73,6 +79,7 @@ const Project: React.FC = () => { {activeModule !== "market" && } {isPlaying && activeModule === "simulation" && } + {selectedUser && }
); }; diff --git a/app/src/store/useCollabStore.ts b/app/src/store/useCollabStore.ts new file mode 100644 index 0000000..3fe1497 --- /dev/null +++ b/app/src/store/useCollabStore.ts @@ -0,0 +1,30 @@ +import { create } from 'zustand'; + +interface SelectedUser { + color: string; + name: string; + location?: { + position: { + x: number; + y: number; + z: number; + }; + rotation: { + x: number; + y: number; + z: number; + }; + } +} + +interface SelectedUserStore { + selectedUser: SelectedUser | null; + setSelectedUser: (user: SelectedUser) => void; + clearSelectedUser: () => void; +} + +export const useSelectedUserStore = create((set) => ({ + selectedUser: null, + setSelectedUser: (user) => set({ selectedUser: user }), + clearSelectedUser: () => set({ selectedUser: null }), +})); diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index 6bb3d57..2913425 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -10,63 +10,97 @@ $text-color: #2b3344; $text-disabled: #b7b7c6; $input-text-color: #595965; $highlight-text-color: #6f42c1; +$text-button-color: #f3f3fd; // ---------- dark mode ---------- $text-color-dark: #f3f3fd; $text-disabled-dark: #6f6f7a; $input-text-color-dark: #b5b5c8; -$highlight-text-color-dark: #B392F0; +$highlight-text-color-dark: #b392f0; +$text-button-color-dark: #f3f3fd; // background colors // ---------- light mode ---------- -$background-color: linear-gradient(-45deg, #FCFDFDCC 0%, #FCFDFD99 100%); -$background-color-secondary: #FCFDFD4D; +$background-color: linear-gradient(-45deg, #fcfdfdcc 0%, #fcfdfd99 100%); +$background-color-solid: #fcfdfd; +$background-color-secondary: #fcfdfd4d; $background-color-accent: #6f42c1; $background-color-button: #6f42c1; -$background-color-drop-down: #6F42C14D; -$background-color-input: #FFFFFF4D; -$background-color-input-focus: #F2F2F7; -$background-color-drop-down-gradient: linear-gradient(-45deg, #75649366 0%, #40257266 100%); -$background-color-selected: #E0DFFF; -$background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); +$background-color-drop-down: #6f42c14d; +$background-color-input: #ffffff4d; +$background-color-input-focus: #f2f2f7; +$background-color-drop-down-gradient: linear-gradient( + -45deg, + #75649366 0%, + #40257266 100% +); +$background-color-selected: #e0dfff; +$background-radial-gray-gradient: radial-gradient( + circle, + #bfe0f8 0%, + #e9ebff 46%, + #e2acff 100% +); // ---------- dark mode ---------- -$background-color-dark: linear-gradient(-45deg, #333333B3 0%, #2D2437B3 100%); -$background-color-secondary-dark: #19191D99; +$background-color-dark: linear-gradient(-45deg, #333333b3 0%, #2d2437b3 100%); +$background-color-solid-dark: #19191d; +$background-color-secondary-dark: #19191d99; $background-color-accent-dark: #6f42c1; $background-color-button-dark: #6f42c1; $background-color-drop-down-dark: #50505080; -$background-color-input-dark: #FFFFFF33; +$background-color-input-dark: #ffffff33; $background-color-input-focus-dark: #333333; -$background-color-drop-down-gradient-dark: linear-gradient(-45deg, #8973B166 0%, #53427366 100%); -$background-color-selected-dark: #403E66; -$background-radial-gray-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); +$background-color-drop-down-gradient-dark: linear-gradient( + -45deg, + #8973b166 0%, + #53427366 100% +); +$background-color-selected-dark: #403e66; +$background-radial-gray-gradient-dark: radial-gradient( + circle, + #31373b 0%, + #48494b 46%, + #52415c 100% +); // border colors // ---------- light mode ---------- -$border-color: #E0DFFF; -$border-color-accent: #6F42C1; +$border-color: #e0dfff; +$input-border-color: #d5dddd80; +$border-color-accent: #6f42c1; // ---------- dark mode ---------- -$border-color-dark: #564B69; -$border-color-accent-dark: #6F42C1; +$border-color-dark: #564b69; +$input-border-color-dark: #d5dddd80; +$border-color-accent-dark: #6f42c1; // highlight colors // ---------- light mode ---------- -$highlight-accent-color: #E0DFFF; -$highlight-secondary-color: #6F42C1; +$highlight-accent-color: #e0dfff; +$highlight-secondary-color: #6f42c1; // ---------- dark mode ---------- -$highlight-accent-color-dark: #403E6A; -$highlight-secondary-color-dark: #C4ABF1; +$highlight-accent-color-dark: #403e6a; +$highlight-secondary-color-dark: #c4abf1; + +// icon colors +// ---------- light mode ---------- +$icon-default-color: #6f42c1; +$icon-default-color-hover: #7f4ddb; +$icon-default-color-active: #f2f2f7; + +// ---------- dark mode ---------- +$icon-default-color-dark: #6f42c1; +$icon-default-color-hover-dark: #7f4ddb; +$icon-default-color-active-dark: #f2f2f7; // colors -$color1: #A392CD; +$color1: #a392cd; $color2: #7b4cd3; -$color3: #B186FF; -$color4: #8752E8; -$color5: #C7A8FF; - +$color3: #b186ff; +$color4: #8752e8; +$color5: #c7a8ff; // old variables $accent-color: #6f42c1; @@ -74,15 +108,15 @@ $accent-color-dark: #c4abf1; $highlight-accent-color: #e0dfff; $highlight-accent-color-dark: #403e6a; -$background-color: #fcfdfd; -$background-color-dark: #19191d; -$background-color-secondary: #e1e0ff80; -$background-color-secondary-dark: #39394f99; +// $background-color: #fcfdfd; +// $background-color-dark: #19191d; +// $background-color-secondary: #e1e0ff80; +// $background-color-secondary-dark: #39394f99; $background-color-gray: #f3f3f3; $background-color-gray-dark: #232323; -$border-color: #e0dfff; -$border-color-dark: #403e6a; +// $border-color: #e0dfff; +// $border-color-dark: #403e6a; $shadow-color: #3c3c431a; $shadow-color-dark: #8f8f8f1a; @@ -91,7 +125,12 @@ $acent-gradient-dark: linear-gradient(90deg, #b392f0 0%, #a676ff 100%); $acent-gradient: linear-gradient(90deg, #6f42c1 0%, #925df3 100%); $faint-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); -$faint-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); +$faint-gradient-dark: radial-gradient( + circle, + #31373b 0%, + #48494b 46%, + #52415c 100% +); $font-inter: "Inter", sans-serif; $font-josefin-sans: "Josefin Sans", sans-serif; @@ -130,3 +169,4 @@ $border-radius-medium: 6px; $border-radius-large: 12px; $border-radius-circle: 50%; $border-radius-extra-large: 20px; +$border-radius-xxx: 30px; diff --git a/app/src/styles/base/base.scss b/app/src/styles/base/base.scss index e74c0ec..10fb87c 100644 --- a/app/src/styles/base/base.scss +++ b/app/src/styles/base/base.scss @@ -1,139 +1,161 @@ -@use "../abstracts/variables" as *; // abstracts/variables.scss +@use "../abstracts/variables" as *; -// Light theme styles [data-theme="light"] { - // Text and Input colors - --text-color: #{$text-color}; // Main text color for light theme - --text-disabled: #{$text-disabled}; // Disabled text color - --input-text-color: #{$input-text-color}; // Input field text color + // text colors + --text-color: #{$text-color}; + --text-disabled: #{$text-disabled}; + --text-button-color: #{$text-button-color}; + --input-text-color: #{$input-text-color}; + --highlight-text-color: #{$highlight-text-color}; - // Accent and Highlight colors - --primary-color: #{$background-color}; // Primary color for light theme - --accent-color: #{$accent-color}; // Primary accent color for light theme - --highlight-accent-color: #{$highlight-accent-color}; // Highlight color for light theme - --accent-gradient-color: #{$acent-gradient}; // Primary accent color for light theme + // background colors + --background-color: #{$background-color}; + --background-color-solid: #{$background-color-solid}; + --background-color-secondary: #{$background-color-secondary}; + --background-color-accent: #{$background-color-accent}; + --background-color-button: #{$background-color-button}; + --background-color-drop-down: #{$background-color-drop-down}; + --background-color-input: #{$background-color-input}; + --background-color-input-focus: #{$background-color-input-focus}; + --background-color-drop-down-gradient: #{$background-color-drop-down-gradient}; + --background-color-selected: #{$background-color-selected}; + --background-radial-gray-gradient: #{$background-radial-gray-gradient}; + + // border colors + --border-color: #{$border-color}; + --input-border-color: #{$input-border-color}; + --border-color-accent: #{$border-color-accent}; + + // highlight colors + --highlight-accent-color: #{$highlight-accent-color}; + --highlight-secondary-color: #{$highlight-secondary-color}; + + // icon colors + --icon-default-color: #{$icon-default-color}; + --icon-default-color-active: #{$icon-default-color-active}; + + // old colors + --accent-color: #{$accent-color}; + --highlight-accent-color: #{$highlight-accent-color}; + --accent-gradient-color: #{$acent-gradient}; --faint-gradient-color: #{$faint-gradient}; - - // Background colors - --background-color: #{$background-color}; // Main background color - --background-color-secondary: #{$background-color-secondary}; // Secondary background color - --background-color-gray: #{$background-color-gray}; // Secondary background color - - // Border colors - --border-color: #{$border-color}; // Border color for light theme - - // Shadow variables - --shadow-main-light: #{$shadow-color}; // Main shadow color - --box-shadow-light: 0px 2px 4px var(--shadow-main-light); // Light shadow - --box-shadow-medium: 0px 4px 8px var(--shadow-main-light); // Medium shadow - --box-shadow-heavy: 0px 8px 16px var(--shadow-main-light); // Heavy shadow - - // Font families - --font-inter: #{$font-inter}; // Inter font family - --font-josefin-sans: #{$font-josefin-sans}; // Josefin Sans font family - --font-poppins: #{$font-poppins}; // Poppins font family - --font-roboto: #{$font-roboto}; // Roboto font family + --background-color-gray: #{$background-color-gray}; + --border-color: #{$border-color}; + --shadow-main-light: #{$shadow-color}; + --box-shadow-light: 0px 2px 4px var(--shadow-main-light); + --box-shadow-medium: 0px 4px 8px var(--shadow-main-light); + --box-shadow-heavy: 0px 8px 16px var(--shadow-main-light); + --font-inter: #{$font-inter}; + --font-josefin-sans: #{$font-josefin-sans}; + --font-poppins: #{$font-poppins}; + --font-roboto: #{$font-roboto}; } -// Dark theme styles [data-theme="dark"] { - // Text and Input colors - --text-color: #{$text-color-dark}; // Main text color for dark theme - --text-disabled: #{$text-disabled-dark}; // Disabled text color - --input-text-color: #{$input-text-color-dark}; // Input field text color + // text colors + --text-color: #{$text-color-dark}; + --text-disabled: #{$text-disabled-dark}; + --text-button-color: #{$text-button-color-dark}; + --input-text-color: #{$input-text-color-dark}; + --highlight-text-color: #{$highlight-text-color-dark}; - // Accent and Highlight colors - --primary-color: #{$highlight-accent-color-dark}; - --accent-color: #{$accent-color-dark}; // Primary accent color for dark theme - --highlight-accent-color: #{$highlight-accent-color-dark}; // Highlight color for dark theme - --accent-gradient-color: #{$acent-gradient-dark}; // Primary accent color for light theme + // background colors + --background-color: #{$background-color-dark}; + --background-color-solid: #{$background-color-solid-dark}; + --background-color-secondary: #{$background-color-secondary-dark}; + --background-color-accent: #{$background-color-accent-dark}; + --background-color-button: #{$background-color-button-dark}; + --background-color-drop-down: #{$background-color-drop-down-dark}; + --background-color-input: #{$background-color-input-dark}; + --background-color-input-focus: #{$background-color-input-focus-dark}; + --background-color-drop-down-gradient: #{$background-color-drop-down-gradient-dark}; + --background-color-selected: #{$background-color-selected-dark}; + --background-radial-gray-gradient: #{$background-radial-gray-gradient-dark}; + + // border colors + --border-color: #{$border-color}; + --input-border-color: #{$input-border-color-dark}; + --border-color-accent: #{$border-color-accent-dark}; + + // highlight colors + --highlight-accent-color: #{$highlight-accent-color-dark}; + --highlight-secondary-color: #{$highlight-secondary-color-dark}; + + // icon colors + --icon-default-color: #{$icon-default-color-dark}; + --icon-default-color-active: #{$icon-default-color-active-dark}; + + // old colors + --accent-color: #{$accent-color-dark}; + --highlight-accent-color: #{$highlight-accent-color-dark}; + --accent-gradient-color: #{$acent-gradient-dark}; --faint-gradient-color: #{$faint-gradient-dark}; - - // Background colors - --background-color: #{$background-color-dark}; // Main background color - --background-color-secondary: #{$background-color-secondary-dark}; // Secondary background color - --background-color-gray: #{$background-color-gray-dark}; // Secondary background color - - // Border colors - --border-color: #{$border-color-dark}; // Border color for dark theme - - // Shadow variables - --shadow-main-dark: #{$shadow-color}; // Main shadow color - --box-shadow-light: 0px 2px 4px var(--shadow-main-dark); // Light shadow - --box-shadow-medium: 0px 4px 8px var(--shadow-main-dark); // Medium shadow - --box-shadow-heavy: 0px 8px 16px var(--shadow-main-dark); // Heavy shadow - - // Font families - --font-inter: #{$font-inter}; // Inter font family - --font-josefin-sans: #{$font-josefin-sans}; // Josefin Sans font family - --font-poppins: #{$font-poppins}; // Poppins font family - --font-roboto: #{$font-roboto}; // Roboto font family + --background-color-gray: #{$background-color-gray-dark}; + --border-color: #{$border-color-dark}; + --shadow-main-dark: #{$shadow-color}; + --box-shadow-light: 0px 2px 4px var(--shadow-main-dark); + --box-shadow-medium: 0px 4px 8px var(--shadow-main-dark); + --box-shadow-heavy: 0px 8px 16px var(--shadow-main-dark); + --font-inter: #{$font-inter}; + --font-josefin-sans: #{$font-josefin-sans}; + --font-poppins: #{$font-poppins}; + --font-roboto: #{$font-roboto}; } -// Root container styles #root { - height: 100vh; // Full viewport height - width: 100vw; // Full viewport width - overflow: hidden; // Prevent scrollbars - background-color: var(--background-color-gray); + height: 100vh; + width: 100vw; + overflow: hidden; + background: var(--background-color-gray); } -// Root overlay styles #root-over { - position: fixed; // Fix overlay to the viewport - top: 0; // Align to the top - left: 0; // Align to the left - z-index: 99; // Ensure high stacking order + position: fixed; + top: 0; + left: 0; + z-index: 99; } body { background: var(--background-color); + --font-size-tiny: #{$tiny}; + --font-size-small: #{$small}; + --font-size-regular: #{$regular}; + --font-size-large: #{$large}; + --font-size-xlarge: #{$xlarge}; + --font-size-xxlarge: #{$xxlarge}; + --font-size-xxxlarge: #{$xxxlarge}; + --font-weight-regular: #{$regular-weight}; + --font-weight-medium: #{$medium-weight}; + --font-weight-bold: #{$bold-weight}; - /* Font Sizes */ - --font-size-tiny: #{$tiny}; // Extra small text - --font-size-small: #{$small}; // Small text - --font-size-regular: #{$regular}; // Default text size - --font-size-large: #{$large}; // Large text size - --font-size-xlarge: #{$xlarge}; // Extra large text size - --font-size-xxlarge: #{$xxlarge}; // Double extra large text size - --font-size-xxxlarge: #{$xxxlarge}; // Triple extra large text size - - /* Font Weights */ - --font-weight-regular: #{$regular-weight}; // Regular font weight - --font-weight-medium: #{$medium-weight}; // Medium font weight - --font-weight-bold: #{$bold-weight}; // Bold font weight + // colors + --color1: #{$color1}; + --color2: #{$color2}; + --color3: #{$color3}; + --color4: #{$color4}; + --color5: #{$color5}; } -/* Apply custom scrollbar styles globally */ ::-webkit-scrollbar { - width: 8px; - /* Width of the scrollbar */ - height: 8px; - /* Height for horizontal scrollbars */ + width: 0px; + height: 0px; } ::-webkit-scrollbar-track { background: transparent; - /* Background of the scrollbar track */ border-radius: 4px; - /* Rounded corners */ } ::-webkit-scrollbar-thumb { - background: var(--accent-color); - /* Scrollbar handle color */ + background: var(--background-color-button); border-radius: 4px; - /* Rounded corners */ - border: 2px solid var(--primary-color); - /* Padding around the scrollbar handle */ } ::-webkit-scrollbar-thumb:hover { - background: var(--accent-color); - /* Handle color on hover */ + background: var(--background-color-button); } ::-webkit-scrollbar-corner { background: transparent; - /* Remove corner styling for scrollable containers */ } diff --git a/app/src/styles/base/global.scss b/app/src/styles/base/global.scss index 3ba017e..d90e6fb 100644 --- a/app/src/styles/base/global.scss +++ b/app/src/styles/base/global.scss @@ -1,5 +1,11 @@ +@use "../abstracts/variables" as *; +@use "../abstracts/mixins" as *; + section, .section{ - padding: 12px; + padding: 4px; outline: 1px solid var(--border-color); - border-radius: 16px; + outline-offset: -1px; + border-radius: #{$border-radius-large}; + background: var(--background-color); + margin: 4px 0; } diff --git a/app/src/styles/components/analysis/ROISummary.scss b/app/src/styles/components/analysis/ROISummary.scss new file mode 100644 index 0000000..c1ba7d5 --- /dev/null +++ b/app/src/styles/components/analysis/ROISummary.scss @@ -0,0 +1,318 @@ +.roiSummary-container { + .roiSummary-wrapper { + background-color: var(--background-color); + + .product-info { + display: flex; + } + + .playBack { + display: flex; + background-color: var(--background-color); + border-radius: 12px; + padding: 6px; + + .info { + span { + font-size: var(--font-size-xlarge); + + &:first-child { + color: #31C756; + } + + &:last-child { + color: var(--text-color); + } + } + } + } + + .roi-details { + display: flex; + align-items: center; + gap: 12px; + + .progress-wrapper { + width: 250px; + display: flex; + flex-direction: column; + gap: 6px; + + .content { + display: flex; + flex-direction: column; + gap: 3px; + align-items: center; + + .key { + font-size: var(--font-size-xlarge); + color: var(--accent-color); + } + } + } + + .roi-progress { + width: 100%; + } + + .metrics { + display: flex; + flex-direction: column; + gap: 6px; + + .metric-item { + width: 100%; + border-radius: 6px; + border: 1px solid #00FF56; + background: #436D51; + display: flex; + flex-direction: column; + padding: 4px 6px; + + &:last-child { + align-items: center; + } + + .metric-label { + font-size: 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .metric-value { + text-align: center; + line-height: 20px; + } + } + + .metric-wrapper { + display: flex; + gap: 6px; + + .metric-item { + background-color: var(--background-color); + border: 1px solid var(--Grays-Gray-6, #F2F2F7); + } + } + } + } + + .cost-breakdown { + background-color: var(--background-color); + border: 1px solid var(--text-disabled); + border-radius: 8px; + padding: 16px; + + .breakdown-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 16px; + + .section-wrapper { + display: flex; + gap: 4px; + align-items: center; + } + + .section-number { + font-size: 20px; + color: #00aaff; + } + + .section-title { + font-size: var(--font-size-regular); + color: var(--text-color); + } + + .expand-icon { + font-size: 16px; + color: var(--text-color); + cursor: pointer; + transform: rotate(90deg); + transition: transform 0.2s linear; + } + + .expand-icon.open { + transform: rotate(0deg); + + } + } + + .breakdown-table { + width: 100%; + border-collapse: collapse; + border-radius: 8px; + + th, + td { + padding: 8px; + text-align: left; + border-top: 1px solid var(--text-disabled); + border-bottom: 1px solid var(--text-disabled); + } + + th:first-child, + td:first-child { + border-left: 1px solid var(--text-disabled); + } + + th:last-child, + td:last-child { + border-right: 1px solid var(--text-disabled); + } + + th { + background-color: var(--background-color); + color: #333; + } + + .total-row, + .net-profit-row { + font-weight: bold; + color: #333; + } + } + } + + .tips-section { + background-color: var(--background-color); + border-radius: 8px; + display: flex; + flex-direction: column; + gap: 6px; + padding: 12px; + + .tip-header { + display: flex; + align-items: center; + + .tip-title { + color: var(--text-color); + font-weight: 600; + } + } + + .tip-description { + span { + font-size: var(--font-size-xlarge); + color: #34C759; + + &:first-child { + color: #34C759; + } + + &:nth-child(2) { + color: #488EF6; + } + } + } + } + + .get-tips-button { + border: none; + border-radius: 5px; + cursor: pointer; + font-size: 14px; + margin-top: 8px; + display: inline-block; + display: flex; + justify-content: flex-end; + background: none; + + .btn { + background-color: var(--accent-color); + color: var(--background-color); + padding: 4px 6px; + border-radius: 5px; + display: inline-block; + font-size: 14px; + text-align: center; + } + } + } + + .semi-circle-wrapper { + width: 100%; + height: 125px; + overflow-y: hidden; + position: relative; + } + + .semi-circle { + width: 100%; + height: 250px; + border-radius: 50%; + position: relative; + transition: background 0.5s ease; + } + + .progress-cover { + position: absolute; + width: 75%; + height: 75%; + top: 12.5%; + left: 12.5%; + background-color: var(--background-color); + border-radius: 50%; + } + + .label-wrapper { + .label { + font-size: var(--font-size-xxxlarge); + } + + position: absolute; + bottom: 0%; + left: 50%; + transform: translate(-50%, 0%); + font-weight: bold; + font-size: 1.2rem; + color: #333; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + } +} + +// Breakdown Table Open/Close Logic + +.breakdown-table-wrapper { + &.closed { + max-height: 0; + padding: 0; + } + + &.open { + max-height: 500px; + } + + + + + + .breakdown-table { + width: 100%; + border-collapse: collapse; + + th, + td { + padding: 10px; + border: 1px solid #ddd; + text-align: left; + } + + .total-row { + background-color: #f4f4f4; + font-weight: bold; + } + + .net-profit-row { + background-color: #dff0d8; + font-weight: bold; + } + } +} \ No newline at end of file diff --git a/app/src/styles/components/analysis/analysis.scss b/app/src/styles/components/analysis/analysis.scss new file mode 100644 index 0000000..0af69c2 --- /dev/null +++ b/app/src/styles/components/analysis/analysis.scss @@ -0,0 +1,277 @@ +.analysis { + position: fixed; + top: 0; + left: 0; + display: flex; + justify-content: space-between; + align-items: start; + width: 100%; + height: 100vh; + // pointer-events: none;k + z-index: 10000; + + .analysis-wrapper { + display: flex; + flex-direction: column; + gap: 12px; + } +} + +.analysis-card { + min-width: 333px; + background: var(--background-color); + border-radius: 20px; + + padding: 8px; + + .analysis-card-wrapper { + background: var(--background-color); + border-radius: 14px; + padding: 16px; + + display: flex; + flex-direction: column; + gap: 14px; + + .card-header { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + + .main-header { + line-height: 20px; + font-size: var(--font-size-regular); + } + } + + .process-container { + display: flex; + flex-direction: column; + + .throughput-value { + font-size: 1rem; + + .value { + font-weight: bold; + font-size: 1.5rem; + } + } + + .progress-bar-wrapper { + display: flex; + gap: 8px; + margin-top: 6px; + } + + .progress-bar { + position: relative; + width: 36px; + height: 4px; + border-radius: 13px; + overflow: hidden; + background: #FBEBD7; + + .bar-fill { + position: absolute; + height: 100%; + top: 0; + left: 0; + background: #FC9D2F; + border-radius: 13px; + } + + .bar-fill.full { + width: 100%; + } + + .bar-fill.partial { + width: 0; // inline style will override this + } + } + } + + .metrics-section { + padding-top: 16px; + border-top: 1px solid var(--background-color-gray); + + .metric { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + margin-bottom: 8px; + + .label { + color: var(--text-color); + } + + .value { + font-weight: bold; + } + } + } + } +} + + +.throughoutSummary { + .throughoutSummary-wrapper { + .process-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 16px; + width: 100%; + + .throughput-value { + font-size: var(--font-size-small); + flex: 1; + display: flex; + flex-direction: column; + + .value { + color: var(--accent-color); + } + + /* Let the text take available space */ + } + + .lineChart { + max-width: 200px; + height: 100px; + position: relative; + + .assetUsage { + text-align: right; + position: absolute; + right: 0; + top: 0; + } + + canvas { + background: transparent; + } + } + } + + .footer { + display: flex; + gap: 16px; // Space between cards + margin-top: 24px; + + .footer-card { + width: 100%; + background: var(--background-color-gray); + border-radius: 6px; + padding: 8px; + display: flex; + flex-direction: column; + gap: 6px; + + &:first-child { + width: 85%; + } + + .header { + font-size: var(--font-size-regular); + } + + .value-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: end; + gap: 6px; + } + } + + .shiftUtilization { + .value-container { + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + + .value { + font-size: var(--font-size-xlarge); + } + + .progress-wrapper { + width: 100%; + display: flex; + gap: 6px; + + .progress { + border-radius: 6px; + height: 5px; + + &:nth-child(1) { + background: #F3C64D; + } + + &:nth-child(2) { + background: #67B3F4; + } + + &:nth-child(3) { + background: #7981F5; + } + } + } + + .progress-indicator { + display: flex; + justify-content: space-between; + width: 100%; + gap: 6px; + + .shift-wrapper { + display: flex; + align-items: center; + gap: 5px; + + /* Align items vertically */ + &:nth-child(1) { + .indicator { + + background: #F3C64D; + } + } + + &:nth-child(2) { + .indicator { + + background: #67B3F4; + } + } + + &:nth-child(3) { + .indicator { + + background: #7981F5; + } + } + + label { + font-size: var(--font-size-small); + position: relative; + } + + .indicator { + display: inline-block; + width: 5px; + height: 5px; + border-radius: 50%; + + } + } + } + } + } + + } + + + } +} \ No newline at end of file diff --git a/app/src/styles/components/confirmationPopUp.scss b/app/src/styles/components/confirmationPopUp.scss index 4bef0ae..e955a79 100644 --- a/app/src/styles/components/confirmationPopUp.scss +++ b/app/src/styles/components/confirmationPopUp.scss @@ -11,7 +11,7 @@ left: 50%; transform: translate(-50%, -50%); z-index: 5; - background-color: var(--background-color); + background: var(--background-color); padding: 14px 12px; border-radius: 6px; @@ -32,7 +32,7 @@ } &:last-child { - background-color: #ffe3e0; + background: #ffe3e0; color: #f65648; } diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index 21554e8..b4e7651 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -5,17 +5,18 @@ input { width: 100%; - padding: 2px 4px; - border-radius: #{$border-radius-small}; - outline: 1px solid var(--border-color); + padding: 4px 8px; + border-radius: #{$border-radius-large}; + outline: 1px solid var(--input-border-color); outline-offset: -1px; border: none; - background: transparent; + background: var(--background-color-input); color: var(--input-text-color); &:focus, &:active { - outline: 1px solid var(--accent-color); + outline: 1px solid var(--border-color-accent); + background: var(--background-color-input-focus); } &:-webkit-autofill, @@ -27,29 +28,34 @@ input { caret-color: var(--input-text-color); // Background styles - background-color: var(--background-color) !important; - -webkit-box-shadow: 0 0 0px 1000px var(--background-color) inset !important; + background: var(--background-color-solid) !important; + -webkit-box-shadow: 0 0 0px 1000px var(--background-color-solid) inset !important; } // File input specific style adjustments &::file-selector-button { font-size: 14px; - color: var(--accent-color); - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); border: none; outline: none; border-radius: #{$border-radius-small}; padding: 2px; cursor: pointer; - - // Hover effect for the file button - &:hover { - color: var(--primary-color); - background-color: var(--accent-color); - } } } +input[type="number"] { + // Chrome, Safari, Edge, Opera + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + // Firefox + -moz-appearance: textfield; +} + .input-value { color: var(--input-text-color); font-size: var(--font-size-regular); @@ -67,9 +73,7 @@ input { color: var(--input-text-color); font-size: var(--font-size-regular); font-weight: var(--font-weight-regular); - border: 1px solid var(--accent-color); outline: none; - border-radius: #{$border-radius-small}; line-height: 26px; padding: 0 8px; } @@ -93,8 +97,8 @@ input { } .active { - background-color: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-button); + color: var(--text-button-color); } } @@ -102,17 +106,17 @@ input { position: sticky; top: 0; padding: 8px 10px; - background: var(--background-color); + width: 100%; z-index: 1; .search-container { @include flex-center; width: 100%; - border-radius: #{$border-radius-small}; - background-color: var(--background-color); - padding: 6px 2px; + border-radius: #{$border-radius-extra-large}; + padding: 3px 2px; position: relative; border: 1px solid var(--border-color); + background: var(--background-color-input-focus); .icon-container { @include flex-center; @@ -129,7 +133,7 @@ input { font-weight: var(--font-weight-regular); border: none; outline: none; - background-color: transparent; + background: transparent; padding-left: 36px; } @@ -141,16 +145,17 @@ input { height: 24px; border: none; cursor: pointer; - background-color: transparent; + background: transparent; &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } } } .active { border: 1px solid var(--accent-color); + background: var(--background-color-input-focus); } } @@ -166,7 +171,7 @@ input { position: absolute; left: 10px; top: 12px; - background-color: var(--background-color); + background: var(--background-color); border-radius: #{$border-radius-small}; box-shadow: var(--box-shadow-medium); z-index: 1; @@ -182,7 +187,7 @@ input { gap: 2px; &:hover { - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); } .icon-container { @@ -197,11 +202,11 @@ input { } .selected { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } } @@ -226,13 +231,12 @@ input { justify-content: space-between; cursor: pointer; border-radius: 6px; - background-color: var(--background-color); } .dropdown-options { position: absolute; width: 100%; - background-color: var(--primary-color); + background: var(--background-color); border: 1px solid var(--border-color); border-radius: #{$border-radius-small}; z-index: 10; @@ -241,6 +245,7 @@ input { left: 0; top: 110%; padding: 4px; + backdrop-filter: blur(8px); .dropdown-search { margin-bottom: 4px; @@ -253,8 +258,8 @@ input { border-radius: #{$border-radius-small}; &:hover { - color: var(--accent-color); - background-color: var(--highlight-accent-color); + color: var(--highlight-text-color); + background: var(--highlight-accent-color); } } } @@ -318,7 +323,7 @@ input { .dropdown-button { width: 100%; - background-color: var(--background-color) !important; + background: var(--background-color) !important; border: 1px solid var(--border-color) !important; padding: 5px 10px; @@ -335,11 +340,11 @@ input { transition: background-color 0.3s ease; &:hover { - background-color: #333333; + background: #333333; } &.open { - background-color: #333333; + background: #333333; } } @@ -347,7 +352,7 @@ input { position: absolute; top: 110%; right: -16px; - background-color: var(--background-color); + background: var(--background-color); border: 1px solid var(--border-color); border-radius: 5px; box-shadow: #{$box-shadow-medium}; @@ -412,7 +417,7 @@ input { transition: background-color 0.3s ease; &:hover { - background-color: var(--background-color); + background: var(--background-color); } } @@ -435,12 +440,12 @@ input { } &:hover { - background-color: var(--background-color); + background: var(--background-color); } &.open { color: var(--accent-color); - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } .icon { @@ -472,20 +477,20 @@ input { } .check-box { - height: 22px; - width: 44px; - background: var(--background-color-secondary); + height: 24px; + width: 38px; + background: var(--background-color); border-radius: #{$border-radius-large}; position: relative; cursor: pointer; .check-box-style { position: absolute; - height: 18px; - width: 18px; + height: 20px; + width: 20px; top: 2px; left: 2px; - background: var(--accent-color); + background: var(--text-button-color); border-radius: #{$border-radius-circle}; transition: left 0.3s ease; } @@ -523,7 +528,7 @@ input { -webkit-appearance: none; width: 16px; height: 16px; - background: var(--primary-color); + background: var(--background-color-accent); border-radius: #{$border-radius-circle}; box-shadow: 0 0 2px rgba(0, 0, 0, 0.2); cursor: pointer; @@ -597,19 +602,19 @@ input { cursor: not-allowed; &::-webkit-slider-thumb { - background: var(--primary-color); + background: var(--background-color-accent); box-shadow: none; outline: 4px solid var(--text-disabled); outline: -4px; } &::-moz-range-thumb { - background: var(--primary-color); + background: var(--background-color-accent); box-shadow: none; } &::-ms-thumb { - background: var(--primary-color); + background: var(--background-color-accent); box-shadow: none; } @@ -644,14 +649,10 @@ input { padding: 2px 32px; border: none; border-radius: #{$border-radius-large}; - color: var(--text-disabled); - background: var(--accent-color); + color: var(--text-color); + background: var(--background-color-button); transition: all 0.2s; cursor: pointer; - - &:hover { - color: var(--primary-color); - } } } @@ -710,11 +711,6 @@ input { line-height: 12px; text-align: center; border-radius: #{$border-radius-small}; - - &:hover { - background: var(--accent-color); - color: var(--primary-color); - } } } } @@ -722,8 +718,8 @@ input { .invite-button { padding: 4px 12px; border-radius: #{$border-radius-large}; - background: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-accent); + color: var(--text-button-color); } .multi-email-invite-input.active { @@ -740,17 +736,17 @@ input { @include flex-center; } } - .upload-custom-asset-button{ + .upload-custom-asset-button { padding: 6px 12px; @include flex-space-between; - .title{ + .title { white-space: nowrap; width: 40%; } - input{ + input { display: none; } - .upload-button{ + .upload-button { width: 60%; background: var(--highlight-accent-color); color: var(--accent-color); @@ -770,7 +766,7 @@ input { width: 100%; height: 100%; border-radius: #{$border-radius-small}; - background-color: var(--background-color-gray); + background: var(--background-color-gray); } } } diff --git a/app/src/styles/components/lists.scss b/app/src/styles/components/lists.scss index cf66d2b..3b52e69 100644 --- a/app/src/styles/components/lists.scss +++ b/app/src/styles/components/lists.scss @@ -30,8 +30,6 @@ } .list-wrapper { - - .no-item { padding: 12px; } @@ -41,7 +39,6 @@ // margin-left: 10px; overflow: hidden; - .list-item { @include flex-space-between; width: 100%; @@ -67,7 +64,7 @@ } .active { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--primary-color); } } @@ -75,7 +72,6 @@ .asset-list { border-left: 2px solid var(--border-color); - margin-left: 20px + margin-left: 20px; } - -} \ No newline at end of file +} diff --git a/app/src/styles/components/marketPlace/marketPlace.scss b/app/src/styles/components/marketPlace/marketPlace.scss index c93b344..b84a252 100644 --- a/app/src/styles/components/marketPlace/marketPlace.scss +++ b/app/src/styles/components/marketPlace/marketPlace.scss @@ -5,28 +5,28 @@ height: 100vh; width: 100vw; z-index: #{$z-index-marketplace}; - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); position: absolute; left: 0; top: 0; padding: 100px 50px; padding-bottom: 32px; - backdrop-filter: blur(6px); - + .marketplace-container { position: relative; padding: 20px 2px; height: 100%; - background-color: var(--background-color); + background: var(--background-color); box-shadow: #{$box-shadow-medium}; - border-radius: #{$border-radius-extra-large}; + border-radius: #{$border-radius-xxx}; + outline: 1px solid var(--border-color); + backdrop-filter: blur(16px); } .marketPlace { width: 100%; height: 100%; overflow: auto; - padding-bottom: 60px; display: flex; flex-direction: column; gap: 24px; @@ -83,12 +83,18 @@ } } } - + .cards-container-wrapper{ + position: relative; + height: calc(100% - 60px); + padding: 0px 10px; + } .cards-container-container { - padding: 0px 20px; display: flex; + padding: 0 10px; flex-direction: column; gap: 6px; + height: 100%; + overflow: auto; .header { color: var(--text-color); @@ -107,7 +113,8 @@ border-radius: 18px; padding: 12px; box-shadow: 0px 2px 10.5px 0px #0000000d; - border: 1px solid var(--background-accent-transparent, #e0dfff80); + background: var(--background-color); + border: 1px solid var(--border-color); position: relative; display: flex; flex-direction: column; @@ -124,7 +131,7 @@ height: 30px; border-radius: 10px; padding: 5px; - background-color: var(--accent-color); + background: var(--accent-color); } .image-container { @@ -193,11 +200,11 @@ .buy-now-button { width: 100%; - background-color: var(--background-color-secondary); + background: var(--background-color-button); border-radius: $border-radius-extra-large; padding: 8px 0; @include flex-center; - color: var(--accent-color); + color: var(--text-button-color); &:hover { cursor: pointer; @@ -220,7 +227,7 @@ .assetPreview { width: 100%; height: 100%; - background-color: var(--background-color); + background: var(--background-color); display: flex; gap: 12px; overflow: hidden; @@ -262,7 +269,7 @@ border-radius: 50%; font-weight: var(--font-weight-bold); color: var(--background-color); - background-color: var(--accent-color); + background: var(--accent-color); } .organization-details { @@ -327,7 +334,7 @@ display: block; width: 2px; height: 12px; - background-color: #ccc; + background: #ccc; } } @@ -363,7 +370,7 @@ } &:last-child { - background-color: var(--accent-color); + background: var(--accent-color); color: var(--background-color); } } diff --git a/app/src/styles/components/menu/menu.scss b/app/src/styles/components/menu/menu.scss index 55b16f9..be9e17f 100644 --- a/app/src/styles/components/menu/menu.scss +++ b/app/src/styles/components/menu/menu.scss @@ -6,15 +6,31 @@ align-items: center; gap: 2px; position: relative; - height: 32px; + border-radius: #{$border-radius-extra-large}; + background: var(--background-color-drop-down); + padding: 3px 8px; + width: fit-content; + max-width: 100%; .project-name { - line-height: 32px; + @include flex-center; height: 100%; + line-height: 26px; + .icon{ + @include flex-center; + height: 20px; + width: 20px; + } + .input-value{ + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } .more-options-button { @include flex-center; border-radius: #{$border-radius-small}; - height: 28px; + height: 22px; position: relative; &:hover { background: var(--highlight-accent-color); @@ -36,11 +52,12 @@ top: 32px; left: 0; z-index: 5; - background-color: var(--background-color); + background: var(--background-color); color: var(--text-color); box-shadow: var(--box-shadow-light); border-radius: 8px; border: 1px solid var(--border-color); + backdrop-filter: blur(10px); .menu-buttons { display: flex; flex-direction: column; @@ -73,7 +90,7 @@ position: absolute; top: 0; left: 100%; - background-color: var(--background-color); + background: var(--background-color); min-width: 220px; border-radius: 4px; box-shadow: var(--box-shadow-light); @@ -95,7 +112,7 @@ rotate: -90deg; } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); span, .menu-item-right span { color: var(--accent-color); @@ -123,7 +140,7 @@ position: absolute; left: 100%; top: 0; - background-color: var(--background-color); + background: var(--background-color); min-width: 200px; border-radius: 0 4px 4px 4px; box-shadow: var(--box-shadow-light); @@ -140,7 +157,7 @@ white-space: nowrap; color: var(--text-color); &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); span { color: var(--accent-color); } @@ -154,7 +171,7 @@ } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); .menu-button { color: var(--accent-color); } @@ -164,7 +181,7 @@ .split { width: 100%; height: 1px; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); margin: 2px 0; } } diff --git a/app/src/styles/components/moduleToggle.scss b/app/src/styles/components/moduleToggle.scss index a6a77c8..c864cbf 100644 --- a/app/src/styles/components/moduleToggle.scss +++ b/app/src/styles/components/moduleToggle.scss @@ -18,7 +18,8 @@ padding: 4px 12px; border-radius: #{$border-radius-extra-large}; box-shadow: var(--box-shadow-medium); - background-color: var(--background-color); + background: var(--background-color); + backdrop-filter: blur(8px); cursor: pointer; overflow: hidden; position: relative; @@ -37,7 +38,7 @@ left: 0; width: 0%; height: 100%; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); transition: width 0.2s; border-radius: #{$border-radius-extra-large}; } @@ -49,15 +50,15 @@ } .active { cursor: default; - background-color: var(--accent-color); + background: var(--background-color-button); &::after{ display: none; } &:hover { - background-color: var(--accent-color); + background: var(--background-color-button); } .module { - color: var(--highlight-accent-color); + color: var(--icon-default-color-active); } } } diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss index eb109c2..9f748f8 100644 --- a/app/src/styles/components/simulation/simulation.scss +++ b/app/src/styles/components/simulation/simulation.scss @@ -3,55 +3,151 @@ .simulation-player-wrapper { position: fixed; - bottom: 32px; + bottom: 50px; left: 50%; z-index: 2; transform: translate(-50%, 0); + width: 70%; + .simulation-player-container { + background-color: var(--background-color); + padding: 7px; + border-radius: 15px; + display: flex; + flex-direction: column; + gap: 8px; + + .progresser-wrapper { + background-color: var(--highlight-accent-color); + padding: 4px 5px; + border-radius: 12px; + display: flex; + flex-direction: column; + gap: 12px; + padding-top: 30px; + transition: height 0.2s linear; + } + + + + .controls-container { @include flex-center; gap: 12px; - margin-bottom: 4px; + justify-content: space-between; + + .production-details, + .controls-wrapper { + display: flex; + gap: 6px; + } + + .production-details { + .production-wrapper { + + display: flex; + align-items: center; + flex-direction: column; + gap: 6px; + + .header { + display: flex; + flex-direction: row; + gap: 6px + } + + .progress-wrapper { + width: 164px; + height: 8px; + border-radius: 5px; + // overflow: hidden; + background-color: var(--highlight-accent-color); + + .progress { + border-radius: 5px; + height: 100%; + background-color: var(--accent-color); + } + } + } + } + .simulation-button-container { @include flex-center; gap: 2px; padding: 6px 8px; min-width: 64px; - background-color: var(--background-color); + background: var(--background-color); border-radius: #{$border-radius-small}; cursor: pointer; + &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); + path { stroke: var(--accent-color); } } } } + .speed-control-container { @include flex-center; gap: 18px; padding: 5px 16px; - background: var(--background-color); + // background: var(--background-color); border-radius: #{$border-radius-medium}; box-sizing: #{$box-shadow-medium}; + border-radius: 20px; + position: relative; + .min-value, .max-value { + display: flex; + align-items: center; font-weight: var(--font-weight-bold); } + .slider-container { - width: 580px; + width: 100%; max-width: 80vw; height: 28px; - background: var(--background-color-gray); + // background: var(--background-color-gray); border-radius: #{$border-radius-small}; position: relative; - padding: 4px 26px; + // padding: 4px 26px; + + + .speed-label { + font-size: var(--font-size-tiny); + position: absolute; + bottom: -4px; + + &:first-child { + left: 0; + } + + &:last-child { + right: 0; + } + } + + &::after { + content: ""; + background-color: #E5E5EA; + position: absolute; + top: 50%; + transform: translate(0, -50%); + width: 100%; + height: 3px; + } + .custom-slider { height: 100%; width: 100%; position: relative; + .slider-input { position: absolute; width: 100%; @@ -60,15 +156,17 @@ z-index: 3; cursor: pointer; } + .slider-handle { position: absolute; + top: 50%; width: 42px; line-height: 20px; text-align: center; background: var(--accent-color); color: var(--primary-color); border-radius: #{$border-radius-small}; - transform: translateX(-50%); + transform: translate(-50%, -50%); cursor: pointer; z-index: 2; } @@ -81,34 +179,184 @@ border-radius: 1px; top: 8px; } - .marker.marker-10{ - left: 10%; + + .marker.marker-10 { + left: 10%; } - .marker.marker-20{ - left: 20%; + + .marker.marker-20 { + left: 20%; } - .marker.marker-30{ - left: 30%; + + .marker.marker-30 { + left: 30%; } - .marker.marker-40{ - left: 40%; + + .marker.marker-40 { + left: 40%; } - .marker.marker-50{ - left: 50%; + + .marker.marker-50 { + left: 50%; } - .marker.marker-60{ - left: 60%; + + .marker.marker-60 { + left: 60%; } - .marker.marker-70{ - left: 70%; + + .marker.marker-70 { + left: 70%; } - .marker.marker-80{ - left: 80%; + + .marker.marker-80 { + left: 80%; } - .marker.marker-90{ - left: 90%; + + .marker.marker-90 { + left: 90%; } } } + + .time-displayer { + display: flex; + justify-content: space-between; + height: auto; + opacity: 1; + // overflow: hidden; + + transition: all 0.5s ease; + + .start-time-wrappper, + .end-time-wrappper { + display: flex; + align-items: center; + gap: 12px; + } + + .time-progresser { + width: 70%; + + .timeline { + padding: 16px; + // background: #f5f3fa; + background: linear-gradient(90.17deg, rgba(255, 255, 255, 0.64) 1.53%, rgba(255, 255, 255, 0.48) 98.13%); + + border-radius: 30px; + display: flex; + align-items: center; + width: 100%; + height: 33px; + + .label-dot-wrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + position: relative; + + .label { + position: absolute; + top: -200%; + transform: translate(0, -0); + font-size: 12px; + color: #666; + white-space: nowrap; + } + + .dot { + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #d3d3e2; + + &.filled { + background-color: #8f5cf2; + + border: 4px solid var(--accent-color); + } + } + } + + .line { + flex-grow: 1; + height: 4px; + background-color: #d3d3e2; + margin: 0 4px; + + &.filled { + background-color: #8f5cf2; + } + } + } + } + } + + + } + + } + +.processDisplayer { + border-radius: 5px; + // overflow: hidden; + background-color: var(--highlight-accent-color); + padding: 14px 6px; + position: relative; + + .process-player { + position: absolute; + top: 50%; + transform: translate(0, -50%); + width: 3.946108102798462px; + height: 26px; + left: 86.81px; + border-radius: 14px; + border-width: 1px; + background: var(--accent-color, #6F42C1); + + } + + .process-wrapper { + display: flex; + // padding: 0px 16px; + + .process { + height: 5px; + background-color: #4caf50; + color: white; + text-align: center; + line-height: 30px; + transition: width 0.3s ease; + } + } + +} + + +.simulation-player-container.open { + + .progresser-wrapper { + padding-top: 4px; + } + + .time-displayer { + height: 0; + opacity: 0; + pointer-events: none; + display: none; + } + + .processDisplayer { + padding: 0; + background: transparent; + + .process-player { + width: 0; + display: none !important; + } + } + +} \ No newline at end of file diff --git a/app/src/styles/components/templates.scss b/app/src/styles/components/templates.scss index e69de29..a2a3da5 100644 --- a/app/src/styles/components/templates.scss +++ b/app/src/styles/components/templates.scss @@ -0,0 +1,22 @@ +.follow-person-container{ + height: 100vh; + width: 100vw; + position: fixed; + top: 0; + left: 0; + outline: 8px solid var(--user-color); + outline-offset: -3px; + border-radius: 16px; + .follower-name{ + background: var(--user-color); + color: #FFFFFF; + padding: 4px 8px; + padding-top: 16px; + text-align: center; + position: absolute; + top: -10px; + left: 50%; + transform: translate(-50%, 0); + border-radius: 8px; + } +} diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index 5a10518..abea736 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -13,14 +13,15 @@ border-radius: #{$border-radius-large}; width: fit-content; transition: width 0.2s; - background-color: var(--background-color); + background: var(--background-color); + backdrop-filter: blur(8px); z-index: #{$z-index-default}; .split { height: 20px; width: 2px; border-radius: 2px; - background: var(--highlight-accent-color); + background: var(--text-disabled); } .draw-tools, @@ -48,10 +49,10 @@ } .active { - background-color: var(--accent-color); + background: var(--background-color-accent); &:hover { - background-color: var(--accent-color); + background: var(--background-color-accent); } } } @@ -91,7 +92,7 @@ padding: 4px; &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); path { @@ -117,7 +118,7 @@ @include flex-center; padding: 3px; border-radius: #{$border-radius-small}; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); gap: 2px; position: relative; @@ -131,7 +132,7 @@ &::after { content: ""; position: absolute; - background-color: var(--accent-color); + background: var(--accent-color); left: 3px; top: 3px; height: 18px; @@ -161,7 +162,7 @@ width: 30px; height: 30px; border-radius: 50%; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); cursor: pointer; @include flex-center; position: fixed; @@ -174,7 +175,7 @@ font-weight: 700; &:hover { font-weight: 500; - background-color: var(--accent-color); + background: var(--accent-color); color: var(--highlight-accent-color); &::after{ animation: pulse 1s ease-out infinite; diff --git a/app/src/styles/components/visualization/floating/common.scss b/app/src/styles/components/visualization/floating/common.scss index d138959..0084e7a 100644 --- a/app/src/styles/components/visualization/floating/common.scss +++ b/app/src/styles/components/visualization/floating/common.scss @@ -3,7 +3,7 @@ .throughput-wrapper, .card { - background-color: var(--background-color); + background: var(--background-color); box-shadow: var(--box-shadow-heavy); @include flex-center; flex-direction: column; @@ -105,7 +105,7 @@ } .productionCapacity-wrapper { - background-color: var(--background-color); + background: var(--background-color); display: flex; flex-direction: column; gap: 6px; @@ -116,7 +116,7 @@ .headeproductionCapacityr-wrapper, .bar-chart { padding: 14px; - background-color: var(--background-color); + background: var(--background-color); display: flex; flex-direction: column; gap: 6px; @@ -276,7 +276,7 @@ .icon { width: 45px; height: 45px; - background-color: var(--accent-color); + background: var(--accent-color); display: flex; justify-content: center; align-items: center; @@ -289,7 +289,7 @@ display: flex; flex-direction: column; gap: 6px; - background-color: var(--background-color); + background: var(--background-color); padding: 14px; .header { @@ -307,7 +307,7 @@ .productivity-dashboard { width: 100%; - background-color: var(--background-color); + background: var(--background-color); color: white; padding: 20px; border-radius: 8px; @@ -324,7 +324,7 @@ } .options { - background-color: #343b47; + background: #343b47; width: 30px; height: 30px; display: flex; @@ -334,7 +334,7 @@ cursor: pointer; &:hover { - background-color: #49505a; + background: #49505a; } } } @@ -350,7 +350,7 @@ gap: 10px; .metric { - background-color: #2c3e50; + background: #2c3e50; padding: 15px; border-radius: 4px; @@ -445,7 +445,7 @@ } .scaleLabels { - background-color: var(--background-color); + background: var(--background-color); box-shadow: var(--box-shadow-heavy); display: flex; justify-content: space-between; diff --git a/app/src/styles/components/visualization/ui/styledWidgets.scss b/app/src/styles/components/visualization/ui/styledWidgets.scss index 794b756..8262bb3 100644 --- a/app/src/styles/components/visualization/ui/styledWidgets.scss +++ b/app/src/styles/components/visualization/ui/styledWidgets.scss @@ -43,7 +43,7 @@ .icon { width: 16.95305824279785px; height: 16.95305824279785px; - background-color: var(--accent-color); + background: var(--accent-color); border-radius: 50%; display: flex; justify-content: center; diff --git a/app/src/styles/layout/loading.scss b/app/src/styles/layout/loading.scss index 0a13753..59354ff 100644 --- a/app/src/styles/layout/loading.scss +++ b/app/src/styles/layout/loading.scss @@ -4,7 +4,7 @@ .loading-wrapper { height: 100vh; width: 100vw; - background: var(--background-color); + background: var(--background-color-solid); .loading-container { position: relative; height: 100%; diff --git a/app/src/styles/layout/popup.scss b/app/src/styles/layout/popup.scss index a354c10..3b31442 100644 --- a/app/src/styles/layout/popup.scss +++ b/app/src/styles/layout/popup.scss @@ -5,13 +5,13 @@ height: 100vh; width: 100vw; background: var(--background-color-secondary); - backdrop-filter: blur(2px); @include flex-center; .collaboration-popup-container { max-width: 50vw; - width: 460px; - background-color: var(--background-color); + width: 520px; + background: var(--background-color); border-radius: #{$border-radius-large}; + backdrop-filter: blur(8px); .split { width: 100%; height: 1px; @@ -88,14 +88,14 @@ .your-name { @include flex-center; gap: 6px; - color: var(--accent-color); + color: var(--text-color); .user-profile{ height: 24px; width: 24px; text-align: center; line-height: 25px; - background-color: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-accent); + color: var(--text-color); border-radius: #{$border-radius-circle}; } } @@ -137,6 +137,7 @@ width: 100%; object-fit: cover; vertical-align: top; + pointer-events: none; } } .user-name{ diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index a102feb..01715ec 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -6,9 +6,10 @@ position: fixed; top: 32px; left: 8px; - background-color: var(--background-color); + background: var(--background-color); backdrop-filter: blur(150px); border-radius: #{$border-radius-extra-large}; + outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; @@ -43,33 +44,40 @@ width: 32px; min-height: 32px; min-width: 32px; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-large}; &:hover { - background-color: var(--background-color-secondary); + outline: 1px solid var(--border-color); + outline-offset: -1px; + background: var(--background-color-drop-down); } } .active { - background-color: var(--background-color-secondary); - outline: 1px solid var(--accent-color); + background: var(--background-color-accent); + outline: 1px solid var(--border-color); outline-offset: -1px; + rect { + stroke: var(--icon-default-color-active); + } + circle { + fill: var(--icon-default-color-active); + } + &:hover { + background: var(--background-color-secondary); + } } } .sidebar-left-container { min-height: 50vh; - padding-bottom: 12px; + padding-bottom: 4px; position: relative; display: flex; flex-direction: column; .sidebar-left-content-container { - border-bottom: 1px solid var(--border-color); - // flex: 1; - // height: calc(100% - 36px); position: relative; - // overflow: auto; .template-list { display: flex; @@ -174,7 +182,7 @@ .stock { padding: 13px 5px; - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); border-radius: 6.33px; display: flex; justify-content: space-between; @@ -231,8 +239,12 @@ .outline-content-container { position: relative; height: 100%; - overflow: auto; - max-height: 60vh; + padding: 8px; + .overflow { + height: calc(100% - 16px); + max-height: 46vh; + overflow: auto; + } } } } @@ -243,15 +255,17 @@ position: fixed; top: 32px; right: 8px; - background-color: var(--background-color); + background: var(--background-color); backdrop-filter: blur(150px); border-radius: #{$border-radius-extra-large}; + outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; .header-container { @include flex-space-between; padding: 10px; + padding-left: 16px; width: 100%; gap: 12px; height: 52px; @@ -262,8 +276,8 @@ .share-button { padding: 4px 12px; - color: var(--primary-color); - background-color: var(--accent-color); + color: var(--text-color); + background: var(--background-color-button); font-weight: var(--font-weight-regular); border-radius: #{$border-radius-large}; cursor: pointer; @@ -277,7 +291,7 @@ .split { height: 20px; width: 2px; - background: var(--background-color-secondary); + background: var(--text-disabled); } .users-container { @@ -320,8 +334,8 @@ display: flex; .user-profile { - background: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-accent); + color: var(--text-button-color); } .user-organization { @@ -346,6 +360,8 @@ .sidebar-actions-container { position: absolute; left: -40px; + background: transparent; + overflow: visible; .sidebar-action-list { margin-bottom: 12px; @@ -353,26 +369,30 @@ height: 34px; width: 34px; border-radius: #{$border-radius-circle}; - background: var(--primary-color); + background: var(--background-color-secondary); + backdrop-filter: blur(8px); box-shadow: #{$box-shadow-medium}; + outline: 1px solid var(--border-color); + outline-offset: -1px; } .active { - background: var(--accent-color); + background: var(--background-color-accent); } } .sidebar-right-container { min-height: 50vh; - padding-bottom: 12px; + padding: 8px; position: relative; overflow: auto; .sidebar-right-content-container { - border-bottom: 1px solid var(--border-color); height: calc(100% - 36px); position: relative; - width: 320px; + width: 304px; + padding-bottom: 10px; + .no-event-selected { color: #666; padding: 1.8rem 1rem; @@ -414,7 +434,7 @@ button { path { stroke: var(--accent-color); - stroke-width: 1.5px; + strokeWidth: 1.5px; } color: var(--accent-color); &:before { @@ -532,7 +552,7 @@ } button { - background-color: transparent; + background: transparent; box-shadow: none; color: #5273eb; padding: 6px; @@ -693,7 +713,7 @@ path { stroke: var(--accent-color); - stroke-width: 1.5px; + strokeWidth: 1.5px; } &:hover { @@ -710,10 +730,10 @@ .machine-mechanics-content-container, .simulations-container, .event-proprties-wrapper { + position: relative; max-height: calc(60vh - (47px - 35px)); - overflow: auto; - overflow-y: scroll; - + width: calc(100% - 4px); + overflow-x: hidden; .header { @include flex-space-between; padding: 6px 12px; @@ -732,7 +752,7 @@ stroke: var(--primary-color); } &:disabled { - background-color: var(--text-disabled); + background: var(--text-disabled); } } } @@ -841,7 +861,7 @@ transform: translateX(4px); &:hover { - background-color: var(--accent-color); + background: var(--accent-color); path { stroke: var(--primary-color); @@ -899,9 +919,8 @@ .collapse-header-container { @include flex-space-between; padding-right: 12px; - margin-top: 8px; - border-top: 1px solid var(--border-color); - border-bottom: 1px solid var(--border-color); + margin: 8px 0; + width: 100%; .header { color: var(--accent-color); @@ -983,11 +1002,8 @@ .zone-properties-container { .header { @include flex-space-between; - padding: 8px 12px; - border-top: 1px solid var(--highlight-accent-color); - border-bottom: 1px solid var(--highlight-accent-color); - color: var(--accent-color); - + padding: 10px 12px; + color: var(--text-color); .input-value { color: inherit; } @@ -995,7 +1011,6 @@ .input-container { @include flex-center; - .remove-button { @include flex-center; height: 18px; @@ -1004,7 +1019,7 @@ border-radius: 8px 0 0 8px; &:hover { - background-color: var(--accent-color); + background: var(--accent-color); path { stroke: var(--primary-color); @@ -1017,8 +1032,8 @@ .generate-report-button, .button-save { @include flex-center; - background-color: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-button); + color: var(--text-button-color); border-radius: #{$border-radius-large}; padding: 2px; gap: 4px; @@ -1028,13 +1043,14 @@ margin-bottom: 8px; } - .split { - height: 1px; - background: var(--highlight-accent-color); - margin: 8px; - } - .custom-input-container { + @include flex-space-between; + .split { + height: 20px; + width: 2px; + border-radius: 2px; + background: var(--text-disabled); + } .header { @include flex-space-between; border: none; @@ -1046,11 +1062,9 @@ .inputs-container { @include flex-space-between; - padding-bottom: 8px; .input-container { padding: 0 12px; - margin-top: 6px; gap: 6px; } } @@ -1068,7 +1082,6 @@ .dropdown-header-container, .dropdown-content-container { padding: 6px 12px; - border-top: 1px solid var(--highlight-accent-color); } .input-range-container { @@ -1162,14 +1175,14 @@ flex-direction: row; flex-wrap: wrap; height: 100%; - gap: 3px; + gap: 8px; padding: 10px 0; .category { - width: 117px; + width: 121px; height: 95px; border-radius: 3.59px; - background-color: var(--background-color-gray); + background: var(--background-color-gray); padding: 8px; padding-top: 12px; font-weight: $bold-weight; @@ -1189,7 +1202,7 @@ width: 60px; height: 60px; border-radius: 50%; - background-color: var(--circle-color, #000); + background: var(--circle-color, #000); position: absolute; top: 60%; right: -10px; @@ -1270,7 +1283,7 @@ width: 117px; height: 95px; border-radius: #{$border-radius-small}; - background-color: var(--background-color-gray); + background: var(--background-color-gray); font-weight: $medium-weight; position: relative; overflow: hidden; @@ -1337,7 +1350,7 @@ width: 117px; height: 95px; border-radius: 3.59px; - background-color: var(--background-color-gray); + background: var(--background-color-gray); padding: 8px; padding-top: 12px; font-weight: $medium-weight; diff --git a/app/src/styles/layout/toast.scss b/app/src/styles/layout/toast.scss index 951a213..eb51c5a 100644 --- a/app/src/styles/layout/toast.scss +++ b/app/src/styles/layout/toast.scss @@ -51,19 +51,19 @@ } .toast.success { - background-color: #4caf50; + background: #4caf50; } .toast.error { - background-color: #f44336; + background: #f44336; } .toast.info { - background-color: #2196f3; + background: #2196f3; } .toast.warning { - background-color: #ff9800; + background: #ff9800; } @keyframes fadeIn { diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss index fe77adb..66a60e7 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -25,6 +25,8 @@ @use 'components/simulation/simulation'; @use 'components/menu/menu'; @use 'components/confirmationPopUp'; +@use 'components/analysis/analysis'; +@use 'components/analysis/ROISummary.scss'; // layout @use 'layout/loading'; diff --git a/app/src/styles/pages/dashboard.scss b/app/src/styles/pages/dashboard.scss index 3fc9a05..a41dc50 100644 --- a/app/src/styles/pages/dashboard.scss +++ b/app/src/styles/pages/dashboard.scss @@ -43,7 +43,7 @@ padding: 12px 16px; cursor: not-allowed; color: var(--accent-color); - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); border-radius: #{$border-radius-large}; } .side-bar-content-container { @@ -66,9 +66,9 @@ .active { color: var(--accent-color); font-weight: var(--font-weight-medium); - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } } } @@ -161,7 +161,7 @@ width: 26px; line-height: 26px; text-align: center; - background-color: var(--accent-color); + background: var(--accent-color); color: var(--primary-color); border-radius: #{$border-radius-circle}; } diff --git a/app/src/styles/pages/home.scss b/app/src/styles/pages/home.scss index 4139cc1..a2db6f7 100644 --- a/app/src/styles/pages/home.scss +++ b/app/src/styles/pages/home.scss @@ -1,38 +1,3 @@ -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: var(--primary-color); - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: 282c34; -} - -.App-link { - color: var(--button-action-color); -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - .navbar{ position: absolute; top: 0; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 1efa2d4..3aa1bd5 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -3,7 +3,7 @@ // Main Container .realTime-viz { - background-color: #131313; + background: #131313; border-radius: 20px; box-shadow: $box-shadow-medium; width: calc(100% - (320px + 270px + 90px)); @@ -66,7 +66,7 @@ .zone-wrapper { display: flex; - background-color: var(--background-color); + background: var(--background-color); position: absolute; bottom: 0px; left: 50%; @@ -84,7 +84,7 @@ } .arrow { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--background-color); } @@ -109,7 +109,7 @@ .zone { width: auto; - background-color: var(--background-color); + background: var(--background-color); border-radius: 6px; padding: 4px 8px; white-space: nowrap; @@ -117,7 +117,7 @@ } .active { - background-color: var(--accent-color); + background: var(--accent-color); color: var(--background-color); // color: #FCFDFD !important; } @@ -138,13 +138,13 @@ position: relative; flex: 1; height: 600px; - background-color: rgb(235, 235, 235); + background: rgb(235, 235, 235); margin: 0 30px; transition: height 0.3s ease, margin 0.3s ease; .zone-wrapper { display: flex; - background-color: rgba(224, 223, 255, 0.5); + background: rgba(224, 223, 255, 0.5); position: absolute; // bottom: 10px; left: 50%; @@ -162,7 +162,7 @@ .zone { width: auto; - background-color: $background-color; + background: $background-color; border-radius: 6px; padding: 4px 8px; white-space: nowrap; @@ -170,7 +170,7 @@ transition: background-color 0.3s ease; &.active { - background-color: var(--primary-color); + background: var(--primary-color); color: var(--accent-color); } } @@ -203,7 +203,7 @@ display: flex; flex-direction: column; gap: 6px; - background-color: var(--background-color); + background: var(--background-color); &::-webkit-scrollbar { display: none; @@ -217,7 +217,7 @@ border-radius: 8px; box-shadow: var(--box-shadow-medium); padding: 6px 0; - background-color: var(--background-color); + background: var(--background-color); position: relative; padding: 0 10px; @@ -237,7 +237,7 @@ top: 18px; right: 5px; transform: translate(0px, 0); - background-color: var(--background-color); + background: var(--background-color); z-index: 10; display: flex; @@ -261,7 +261,7 @@ } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); width: 100%; svg { @@ -353,7 +353,7 @@ border-radius: 8px; box-shadow: var(--box-shadow-medium); padding: 6px 0; - background-color: var(--background-color); + background: var(--background-color); position: relative; } } @@ -377,7 +377,7 @@ .side-button-container { position: absolute; display: flex; - background-color: var(--background-color); + background: var(--background-color); padding: 2px; border-radius: 2px; transition: transform 0.3s ease; @@ -398,7 +398,7 @@ } .active { - background-color: var(--accent-color); + background: var(--accent-color); } &:hover { @@ -414,7 +414,7 @@ display: flex; justify-content: center; // align-items: center; - background-color: var(--accent-color); + background: var(--accent-color); border: none; color: var(--background-color); border-radius: 4px; @@ -494,7 +494,7 @@ padding: 12px; box-shadow: 1px -3px 4px 0px rgba(0, 0, 0, 0.11); border-radius: 8px; - background-color: white; + background: white; position: absolute; top: 20px; right: -100%; @@ -530,7 +530,7 @@ left: 1px; width: 10px; height: 10px; - background-color: var(--primary-color); + background: var(--primary-color); border-radius: 50%; } } @@ -584,7 +584,7 @@ } .zone.active { - background-color: #007bff; + background: #007bff; color: white; } @@ -592,7 +592,7 @@ .icon { // width: 25px !important; // height: 25px !important; - // background-color: transparent; + // background: transparent; } .kebab { @@ -604,7 +604,7 @@ z-index: 10; cursor: pointer; @include flex-center; - background-color: transparent !important; + background: transparent !important; } .kebab-options { @@ -612,7 +612,7 @@ top: 18px; right: 5px; transform: translate(0px, 0); - background-color: var(--background-color); + background: var(--background-color); z-index: 10; display: flex; @@ -625,7 +625,7 @@ .icon { width: 25px !important; height: 25px !important; - background-color: transparent; + background: transparent; } .btn { @@ -643,7 +643,7 @@ } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); width: 100%; svg { @@ -662,6 +662,7 @@ } .distance-line { + position: absolute; border-style: dashed; border-color: var(--accent-color); @@ -675,7 +676,7 @@ /* Label styles for displaying distance values */ .distance-label { position: absolute; - background-color: var(--accent-color); + background: var(--accent-color); color: white; font-size: 12px; padding: 2px 6px; @@ -769,7 +770,8 @@ .editWidgetOptions { position: absolute; - background-color: var(--background-color); + background: var(--background-color); + backdrop-filter: blur(10px); z-index: 3; display: flex; flex-direction: column; @@ -786,7 +788,7 @@ cursor: pointer; &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); } @@ -794,7 +796,7 @@ color: #f65648; &:hover { - background-color: #f657484d; + background: #f657484d; color: #f65648; } } diff --git a/app/src/styles/pages/userAuth.scss b/app/src/styles/pages/userAuth.scss index 6e86ac1..9d07dcf 100644 --- a/app/src/styles/pages/userAuth.scss +++ b/app/src/styles/pages/userAuth.scss @@ -9,7 +9,7 @@ padding: 20px; color: var(--text-color); height: 100vh; - background-color: var(--background-color); + background: var(--background-color); position: relative; z-index: 1; .logo-icon { diff --git a/app/src/styles/scene/scene.scss b/app/src/styles/scene/scene.scss index fc3b824..ab8f787 100644 --- a/app/src/styles/scene/scene.scss +++ b/app/src/styles/scene/scene.scss @@ -14,9 +14,8 @@ // style font-size: var(--font-size-large); padding: 2px 8px; - background: var(--primary-color); - color: var(--accent-color); - outline: 1px solid var(--accent-color); + background: var(--background-color-accent); + color: var(--text-color); border-radius: #{$border-radius-medium}; box-shadow: var(--box-shadow-light); } diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 3293699..811812d 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -44,8 +44,8 @@ interface VehiclePointSchema { actionType: "travel"; unLoadDuration: number; loadCapacity: number; - pickUpPoint: { x: number; y: number, z: number } | null; - unLoadPoint: { x: number; y: number, z: number } | null; + pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; + unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; triggers: TriggerSchema[]; }; } @@ -134,7 +134,7 @@ interface ConveyorStatus extends ConveyorEventSchema { isActive: boolean; idleTime: number; activeTime: number; - + } interface MachineStatus extends MachineEventSchema { diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index 924c12c..0374c8a 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -189,10 +189,10 @@ export const firstPersonControls: Controls = { maxDistance: 0, // Maximum distance from the target maxPolarAngle: Math.PI, // Maximum polar angle leftMouse: 1, // Mouse button for rotation (ROTATE) - forwardSpeed: 0.3, // Speed of forward movement - backwardSpeed: -0.3, // Speed of backward movement - leftSpeed: -0.3, // Speed of left movement - rightSpeed: 0.3, // Speed of right movement + forwardSpeed: 0.1, // Speed of forward movement + backwardSpeed: -0.1, // Speed of backward movement + leftSpeed: -0.1, // Speed of left movement + rightSpeed: 0.1, // Speed of right movement }; export const thirdPersonControls: ThirdPersonControls = { diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 43ca553..52877b9 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -190,7 +190,7 @@ const KeyPressListener: React.FC = () => { return () => { window.removeEventListener("keydown", handleKeyPress); }; - }, [activeModule, toggleUI, toggleView]); // Dependencies to reapply effect if these values change + }, [activeModule, setActiveModule, setActiveSubTool, setActiveTool, setAddAction, setDeleteTool, setIsPlaying, setSelectedWallItem, setToggleThreeD, setToggleUI, setToggleView, setToolMode, toggleUI, toggleView]); // Dependencies to reapply effect if these values change return null; // This component does not render any UI };