From db162c9ffaebe7a955b94a187596467fca5d1316 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Fri, 2 May 2025 16:43:43 +0530 Subject: [PATCH 1/2] refactor: Update icon imports and improve UI components; enhance styles for better layout and responsiveness; modify event properties and simulation player functionality --- .../components/icons/ExportCommonIcons.tsx | 4 +- .../components/layout/sidebarLeft/Header.tsx | 4 +- .../layout/sidebarRight/analysis/Analysis.tsx | 64 ++---- .../properties/GlobalProperties.tsx | 4 +- .../eventProperties/EventProperties.tsx | 216 +++++++++--------- .../ui/simulation/simulationPlayer.tsx | 167 ++++++++------ .../visualization/RealTimeVisulization.tsx | 2 - .../components/simulation/simulation.scss | 13 +- app/src/styles/components/tools.scss | 2 + app/src/styles/layout/sidebar.scss | 28 +-- 10 files changed, 252 insertions(+), 252 deletions(-) diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index eaa7701..6925853 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -458,7 +458,7 @@ export function InfoIcon() { > { -
{ if (activeModule !== "market") { @@ -29,7 +29,7 @@ const Header: React.FC = () => { }} > -
+ ); }; diff --git a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx index 9d2889f..9b16186 100644 --- a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx +++ b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { AI_Icon } from "../../../icons/ExportCommonIcons"; +import { AIIcon } from "../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../ui/inputs/RegularDropDown"; import { AnalysisPresetsType } from "../../../../types/analysis"; import RenderAnalysisInputs from "./RenderAnalysisInputs"; @@ -13,53 +13,24 @@ const Analysis: React.FC = () => { const AnalysisPresets: AnalysisPresetsType = { "Throughput time": [ - { type: "default", inputs: { label: "Height", activeOption: "mm" } }, - { type: "default", inputs: { label: "Width", activeOption: "mm" } }, - { type: "default", inputs: { label: "Length", activeOption: "mtr" } }, - { type: "default", inputs: { label: "Thickness", activeOption: "mm" } }, - { - type: "default", - inputs: { label: "Raw Material", activeOption: "mm" }, - }, - { - type: "range", - inputs: { label: "Material flow", activeOption: "m/min" }, - }, + { type: "default", inputs: { label: "Cycle time", activeOption: "s" } }, + { type: "default", inputs: { label: "machines / lines", activeOption: "item" } }, + { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } }, ], "Production capacity": [ - { type: "default", inputs: { label: "Height", activeOption: "mm" } }, - { type: "default", inputs: { label: "Width", activeOption: "mm" } }, - { type: "default", inputs: { label: "Length", activeOption: "mtr" } }, - { type: "default", inputs: { label: "Thickness", activeOption: "mm" } }, - { - type: "default", - inputs: { label: "Raw Material", activeOption: "mm" }, - }, - { - type: "range", - inputs: { label: "Material flow", activeOption: "m/min" }, - }, - { - type: "range", - inputs: { label: "Shift 1", activeOption: "hr(s)" }, - }, - { - type: "range", - inputs: { label: "Shift 2", activeOption: "hr(s)" }, - }, - { - type: "range", - inputs: { label: "Over time", activeOption: "hr(s)" }, - }, + { type: "default", inputs: { label: "Shift length", activeOption: "hr" } }, + { type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } }, + { type: "default", inputs: { label: "Working days / year", activeOption: "days" } }, + { type: "default", inputs: { label: "Yield rate", activeOption: "%" } }, ], ROI: [ { type: "default", - inputs: { label: "Equipment Cost", activeOption: "INR" }, + inputs: { label: "Selling price", activeOption: "INR" }, }, { type: "default", - inputs: { label: "Employee Salary", activeOption: "INR" }, + inputs: { label: "Material cost", activeOption: "INR" }, }, { type: "default", @@ -67,7 +38,7 @@ const Analysis: React.FC = () => { }, { type: "default", - inputs: { label: "Cost per unit", activeOption: "INR" }, + inputs: { label: "Maintenance cost", activeOption: "INR" }, }, { type: "default", @@ -75,20 +46,19 @@ const Analysis: React.FC = () => { }, { type: "default", - inputs: { label: "Upkeep Cost", activeOption: "INR" }, + inputs: { label: "Fixed costs", activeOption: "INR" }, }, { type: "default", - inputs: { label: "Working Hours", activeOption: "Hrs" }, + inputs: { label: "Salvage value", activeOption: "Hrs" }, }, { type: "default", - inputs: { label: "Power Usage", activeOption: "KWH" }, + inputs: { label: "Production period", activeOption: "yrs" }, }, - { type: "default", inputs: { label: "KWH", activeOption: "Mos" } }, { type: "default", - inputs: { label: "Man Power", activeOption: "Person" }, + inputs: { label: "Tax rate", activeOption: "%" }, }, ], }; @@ -98,7 +68,7 @@ const Analysis: React.FC = () => {
Object
- Generate Report + Generate Report
@@ -121,7 +91,7 @@ const Analysis: React.FC = () => { />
- +
Create Custom Analysis
diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 8b91afc..514808a 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import InputRange from "../../../ui/inputs/InputRange"; import InputToggle from "../../../ui/inputs/InputToggle"; -import { AI_Icon } from "../../../icons/ExportCommonIcons"; +import { AIIcon } from "../../../icons/ExportCommonIcons"; import LabeledButton from "../../../ui/inputs/LabledButton"; import { useAzimuth, @@ -225,7 +225,7 @@ const GlobalProperties: React.FC = () => {
Environment
- + Optimize
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 4fa9105..053fc14 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from "react"; import { - useSelectedEventData, - useSelectedEventSphere, - useSelectedProduct, + useSelectedEventData, + useSelectedEventSphere, + useSelectedProduct, } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -15,114 +15,118 @@ import { handleAddEventToProduct } from "../../../../../modules/simulation/event import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; const EventProperties: React.FC = () => { - const { selectedEventData } = useSelectedEventData(); - const { getEventByModelUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const [currentEventData, setCurrentEventData] = useState(null); - const [assetType, setAssetType] = useState(null); - const { products, addEvent } = useProductStore(); - const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const [currentEventData, setCurrentEventData] = useState( + null + ); + const [assetType, setAssetType] = useState(null); + const { products, addEvent } = useProductStore(); + const { selectedEventSphere } = useSelectedEventSphere(); - useEffect(() => { - const event = getCurrentEventData(); - setCurrentEventData(event); + useEffect(() => { + const event = getCurrentEventData(); + setCurrentEventData(event); - const type = determineAssetType(event); - setAssetType(type); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedEventData, selectedProduct]); - - const getCurrentEventData = () => { - if (!selectedEventData?.data || !selectedProduct) return null; - return ( - getEventByModelUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid - ) ?? null - ); - }; - - const determineAssetType = (event: EventsSchema | null) => { - if (!event) return null; - - switch (event.type) { - case "transfer": - return "conveyor"; - case "vehicle": - return "vehicle"; - case "roboticArm": - return "roboticArm"; - case "machine": - return "machine"; - case "storageUnit": - return "storageUnit"; - default: - return null; - } - }; + const type = determineAssetType(event); + setAssetType(type); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedEventData, selectedProduct]); + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; return ( -
- {currentEventData && ( - <> -
-
- {selectedEventData?.data.modelName} -
-
- {assetType === "conveyor" && } - {assetType === "vehicle" && } - {assetType === "roboticArm" && } - {assetType === "machine" && } - {assetType === "storageUnit" && } - - )} - {!currentEventData && selectedEventSphere && ( -
-

- Oops! It looks like this object doesn't have an - event assigned yet. To continue, please link it to one of the - products below. -

- -
-

- Here are some products you can add it to: -

-
    - {products.map((product) => ( -
  • - -
  • - ))} -
-
-
- ) - } - {!selectedEventSphere && ( -
-

- Oops! It looks like you haven't selected an event - point yet. Please select an event to view its properties. -

-
- )} -
+ getEventByModelUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid + ) ?? null ); + }; + + const determineAssetType = (event: EventsSchema | null) => { + if (!event) return null; + + switch (event.type) { + case "transfer": + return "conveyor"; + case "vehicle": + return "vehicle"; + case "roboticArm": + return "roboticArm"; + case "machine": + return "machine"; + case "storageUnit": + return "storageUnit"; + default: + return null; + } + }; + + return ( +
+ {currentEventData && ( + <> +
+
+ {selectedEventData?.data.modelName} +
+
+ {assetType === "conveyor" && } + {assetType === "vehicle" && } + {assetType === "roboticArm" && } + {assetType === "machine" && } + {assetType === "storageUnit" && } + + )} + {!currentEventData && selectedEventSphere && ( +
+

+ Oops! It looks like this object doesn't have an + event assigned yet. To continue, please link it to one of the + products below. +

+ +
+

+ Here are some products you can add it to: +

+
+ {products.map((product) => ( + + ))} +
+
+
+ )} + {!selectedEventSphere && ( +
+

+ Oops! It looks like you haven't selected an event + point yet. Please select an event to view its properties. +

+
+ )} +
+ ); }; export default EventProperties; diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 4c7c76d..901c537 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -12,25 +12,28 @@ import { EndIcon, ExpandIcon, HourlySimulationIcon, + InfoIcon, MonthlyROI, SpeedIcon, StartIcon, } from "../../icons/ExportCommonIcons"; import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; +import { useSubModuleStore } from "../../../store/useModuleStore"; const SimulationPlayer: React.FC = () => { const MAX_SPEED = 8; // Maximum speed + const isDragging = useRef(false); + const sliderRef = useRef(null); const [expand, setExpand] = useState(true); + const [playSimulation, setPlaySimulation] = useState(false); const { speed, setSpeed } = useAnimationPlaySpeed(); - const [playSimulation, setPlaySimulation] = useState(false); const { setIsPlaying } = usePlayButtonStore(); - const sliderRef = useRef(null); - const isDragging = useRef(false); const { setActiveTool } = useActiveTool(); const { isPaused, setIsPaused } = usePauseButtonStore(); const { isReset, setReset } = useResetButtonStore(); + const { subModule } = useSubModuleStore(); // Button functions const handleReset = () => { @@ -114,7 +117,7 @@ const SimulationPlayer: React.FC = () => { }; // Store colors for each process item - const [processColors, setProcessColors] = useState([]); + const [_, setProcessColors] = useState([]); // Generate colors on mount or when process changes useEffect(() => { @@ -162,50 +165,60 @@ const SimulationPlayer: React.FC = () => {
-
- {/* hourlySimulation */} -
-
-
- + {subModule === "analysis" && ( +
+ {/* hourlySimulation */} +
+
+
+ +
+
Hourly Simulation
+
+
+
-
Hourly Simulation
-
-
+ {/* dailyProduction */} +
+
+
+ +
+
Daily Production
+
+
+
+
+
+ {/* monthlyROI */} +
+
+
+ +
+
Monthly ROI
+
+
+
+
{" "}
- {/* dailyProduction */} -
-
-
- -
-
Daily Production
-
-
-
-
+ )} + {subModule === "simulations" && ( +
+ + {playSimulation + ? "Paused - system idle." + : "Running simulation..."}
- {/* monthlyROI */} -
-
-
- -
-
Monthly ROI
-
-
-
-
{" "} -
-
+ )}
- + {subModule === "analysis" && ( + + )}
@@ -330,37 +345,39 @@ const SimulationPlayer: React.FC = () => {
-
-
00:00
-
24:00
-
+ {subModule === "analysis" && ( +
+
00:00
+
24:00
- {process.map((item, index) => ( -
+
+ {process.map((item, index) => (
-
- ))} + key={index} + className="process" + style={{ + width: `${item.completed}%`, + backgroundColor: getAvatarColor(index), + }} + > +
+
+ ))} +
-
+ )}
); diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index caf37a1..ad24e58 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -76,8 +76,6 @@ const RealTimeVisulization: React.FC = () => { const { setSelectedChartId } = useWidgetStore(); const [waitingPanels, setWaitingPanels] = useState(null); - console.log("waitingPanels: ", waitingPanels); - OuterClick({ contextClassName: [ "chart-container", diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss index 0fc3df8..f40ead1 100644 --- a/app/src/styles/components/simulation/simulation.scss +++ b/app/src/styles/components/simulation/simulation.scss @@ -32,10 +32,17 @@ } .controls-container { - @include flex-center; + @include flex-space-between; gap: 12px; justify-content: space-between; - + .header{ + @include flex-center; + gap: 6px; + padding: 0 8px; + svg{ + scale: 1.3; + } + } .production-details, .controls-wrapper { @include flex-center; @@ -72,7 +79,7 @@ .expand-icon-container { @include flex-center; - padding: 6px 8px; + padding: 0 8px; cursor: pointer; } diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index e476c3c..0a23871 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -124,6 +124,8 @@ padding: 4px; border-radius: #{$border-radius-medium}; background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; gap: 5px; position: relative; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index c7f1694..f23d08e 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -58,12 +58,8 @@ fill: var(--icon-default-color-active); } &:hover { - rect { - stroke: var(--icon-default-color); - } - circle { - fill: var(--icon-default-color); - } + filter: saturate(0.8); + background: var(--background-color-accent); } } } @@ -714,10 +710,10 @@ .add-button { @include flex-center; - padding: 2px 4px; + padding: 4px 8px; background: var(--background-color-button); color: var(--text-button-color); - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-large}; cursor: pointer; outline: none; border: none; @@ -832,10 +828,10 @@ transform: translateX(4px); &:hover { - background: var(--accent-color); + background: var(--background-color-accent); path { - stroke: var(--primary-color); + stroke: var(--text-button-color); } } } @@ -1003,10 +999,10 @@ border-radius: 8px 0 0 8px; &:hover { - background: var(--accent-color); + background: var(--background-color-accent); path { - stroke: var(--primary-color); + stroke: var(--text-button-color); } } } @@ -1067,7 +1063,13 @@ .dropdown-content-container { padding: 6px 12px; } - + .value-field-container { + padding: 6px; + .dropdown { + min-width: 44px; + text-align: center; + } + } .input-range-container { .input-container { width: 75%; From 44e3f5c207cf5090186bbb85575046dc606e3b90 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Fri, 2 May 2025 17:39:11 +0530 Subject: [PATCH 2/2] Refactor RealTimeVisualization component and handle widget drop functionality - Commented out the handleDrop function in RealTimeVisualization.tsx and moved its logic to a new utility function createHandleDrop for better separation of concerns. - Updated Project.tsx to utilize the new createHandleDrop function, improving readability and maintainability. - Enhanced styling for the scene container and real-time visualization components to improve layout and responsiveness. - Removed unnecessary styles and consolidated button and input styles for consistency. - Cleaned up unused imports and variables in various files to streamline the codebase. --- app/src/components/icons/SimulationIcons.tsx | 12 +- app/src/components/ui/Tools.tsx | 497 +++++++++--------- .../ui/simulation/simulationPlayer.tsx | 435 +++++++-------- .../visualization/RealTimeVisulization.tsx | 193 +++---- .../visualization/functions/handleUiDrop.ts | 122 +++++ app/src/pages/Project.tsx | 81 ++- .../visualization/useDroppedObjectsStore.ts | 1 - app/src/styles/base/global.scss | 32 +- app/src/styles/base/reset.scss | 7 - .../components/analysis/ROISummary.scss | 16 +- .../styles/components/analysis/analysis.scss | 466 ++++++++-------- app/src/styles/components/button.scss | 24 + app/src/styles/components/input.scss | 15 - app/src/styles/components/tools.scss | 2 +- app/src/styles/pages/realTimeViz.scss | 26 +- 15 files changed, 1031 insertions(+), 898 deletions(-) create mode 100644 app/src/modules/visualization/functions/handleUiDrop.ts diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index ef23c8f..1e89a51 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -125,21 +125,21 @@ export function ResetIcon() { > @@ -158,7 +158,7 @@ export function PlayStopIcon() { > @@ -177,7 +177,7 @@ export function ExitIcon() { > diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 21ea6a7..14bc517 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -36,7 +36,6 @@ import { import useToggleStore from "../../store/useUIToggleStore"; import { use3DWidget, - useDroppedObjectsStore, useFloatingWidget, } from "../../store/visualization/useDroppedObjectsStore"; @@ -57,20 +56,18 @@ const Tools: React.FC = () => { const { widgets3D } = use3DWidget(); - const zones = useDroppedObjectsStore((state) => state.zones); - // wall options const { toggleView, setToggleView } = useToggleView(); const { setDeleteTool } = useDeleteTool(); const { setAddAction } = useAddAction(); const { setSelectedWallItem } = useSelectedWallItem(); - const { transformMode, setTransformMode } = useTransformMode(); - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { movePoint, setMovePoint } = useMovePoint(); - const { toolMode, setToolMode } = useToolMode(); + const { setTransformMode } = useTransformMode(); + const { setDeletePointOrLine } = useDeletePointOrLine(); + const { setMovePoint } = useMovePoint(); + const { setToolMode } = useToolMode(); const { activeTool, setActiveTool } = useActiveTool(); - const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); + const { setRefTextUpdate } = useRefTextUpdate(); // Reset activeTool whenever activeModule changes useEffect(() => { @@ -209,268 +206,266 @@ const Tools: React.FC = () => { return ( <> {!isPlaying ? ( - <> -
-
-
- {activeSubTool == "cursor" && ( -
{ - setActiveTool("cursor"); - }} - > - -
- )} - {activeSubTool == "free-hand" && ( -
{ - setActiveTool("free-hand"); - }} - > - -
- )} - {activeSubTool == "delete" && ( -
{ - setActiveTool("delete"); - }} - > - -
- )} - {activeModule !== "visualization" && ( -
{ - setOpenDrop(!openDrop); - }} - > - - {openDrop && ( -
-
{ - setOpenDrop(false); - setActiveTool("cursor"); - setActiveSubTool("cursor"); - }} - > -
- {activeSubTool === "cursor" && } -
- -
Cursor
-
-
{ - setOpenDrop(false); - setActiveTool("free-hand"); - setActiveSubTool("free-hand"); - }} - > -
- {activeSubTool === "free-hand" && } -
- -
Free Hand
-
-
{ - setOpenDrop(false); - setActiveTool("delete"); - setActiveSubTool("delete"); - }} - > -
- {activeSubTool === "delete" && } -
- -
Delete
-
-
- )} -
- )} -
-
- {!toggleThreeD && activeModule === "builder" && ( - <> -
-
-
{ - setActiveTool("draw-wall"); - }} - title="Wall" - > - -
-
{ - setActiveTool("draw-zone"); - }} - title="Zone" - > - -
-
{ - setActiveTool("draw-aisle"); - }} - title="Aisle" - > - -
-
{ - setActiveTool("draw-floor"); - }} - title="Floor" - > - -
-
- - )} - {activeModule === "builder" && ( - <> -
-
-
{ - setActiveTool("measure"); - }} - title="Measure" - > - -
-
- - )} - {activeModule === "simulation" && ( - <> -
-
-
{ - setActiveTool("pen"); - }} - > - -
-
- - )} - {activeModule === "visualization" && ( - <> -
-
-
{ - handleSaveTemplate({ - addTemplate, - floatingWidget, - widgets3D, - selectedZone, - templates, - visualizationSocket, - }); - }} - > - -
-
- - )} -
-
-
{ - setActiveTool("comment"); - }} - > - -
- {toggleThreeD && ( +
+
+
+ {activeSubTool == "cursor" && (
{ - setIsPlaying(!isPlaying); + setActiveTool("cursor"); }} > - + +
+ )} + {activeSubTool == "free-hand" && ( +
{ + setActiveTool("free-hand"); + }} + > + +
+ )} + {activeSubTool == "delete" && ( +
{ + setActiveTool("delete"); + }} + > + +
+ )} + {activeModule !== "visualization" && ( +
{ + setOpenDrop(!openDrop); + }} + > + + {openDrop && ( +
+
{ + setOpenDrop(false); + setActiveTool("cursor"); + setActiveSubTool("cursor"); + }} + > +
+ {activeSubTool === "cursor" && } +
+ +
Cursor
+
+
{ + setOpenDrop(false); + setActiveTool("free-hand"); + setActiveSubTool("free-hand"); + }} + > +
+ {activeSubTool === "free-hand" && } +
+ +
Free Hand
+
+
{ + setOpenDrop(false); + setActiveTool("delete"); + setActiveSubTool("delete"); + }} + > +
+ {activeSubTool === "delete" && } +
+ +
Delete
+
+
+ )}
)}
- {activeModule === "builder" && ( - <> -
+
+ {!toggleThreeD && activeModule === "builder" && ( + <> +
+
{ + setActiveTool("draw-wall"); + }} + title="Wall" > -
- 2d -
-
- 3d -
+
- +
{ + setActiveTool("draw-zone"); + }} + title="Zone" + > + +
+
{ + setActiveTool("draw-aisle"); + }} + title="Aisle" + > + +
+
{ + setActiveTool("draw-floor"); + }} + title="Floor" + > + +
+
+ + )} + {activeModule === "builder" && ( + <> +
+
+
{ + setActiveTool("measure"); + }} + title="Measure" + > + +
+
+ + )} + {activeModule === "simulation" && ( + <> +
+
+
{ + setActiveTool("pen"); + }} + > + +
+
+ + )} + {activeModule === "visualization" && ( + <> +
+
+
{ + handleSaveTemplate({ + addTemplate, + floatingWidget, + widgets3D, + selectedZone, + templates, + visualizationSocket, + }); + }} + > + +
+
+ + )} +
+
+
{ + setActiveTool("comment"); + }} + > + +
+ {toggleThreeD && ( +
{ + setIsPlaying(!isPlaying); + }} + > + +
)}
- + {activeModule === "builder" && ( + <> +
+
+
+ 2d +
+
+ 3d +
+
+ + )} +
) : ( <> {activeModule !== "simulation" && ( -
setIsPlaying(false)}> +
+ )} )} diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 901c537..e569250 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -19,6 +19,9 @@ import { } from "../../icons/ExportCommonIcons"; import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; import { useSubModuleStore } from "../../../store/useModuleStore"; +import ProductionCapacity from "../analysis/ProductionCapacity"; +import ThroughputSummary from "../analysis/ThroughputSummary"; +import ROISummary from "../analysis/ROISummary"; const SimulationPlayer: React.FC = () => { const MAX_SPEED = 8; // Maximum speed @@ -162,224 +165,236 @@ const SimulationPlayer: React.FC = () => { }; return ( -
-
-
- {subModule === "analysis" && ( -
- {/* hourlySimulation */} -
-
-
- -
-
Hourly Simulation
-
-
-
-
-
- {/* dailyProduction */} -
-
-
- -
-
Daily Production
-
-
-
-
-
- {/* monthlyROI */} -
-
-
- -
-
Monthly ROI
-
-
-
-
{" "} -
-
- )} - {subModule === "simulations" && ( -
- - {playSimulation - ? "Paused - system idle." - : "Running simulation..."} -
- )} -
- - - + <> +
+
+
{subModule === "analysis" && ( - - )} -
-
-
-
-
-
- -
-
-
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 -
-
-
0.5X
-
-
-
-
-
-
-
-
-
-
- - -
-
4x
-
-
-
- {subModule === "analysis" && ( -
-
00:00
-
24:00
-
-
- {process.map((item, index) => ( -
+
+ {/* hourlySimulation */} +
+
+
+ +
+
Hourly Simulation
+
+
- ))} +
+ {/* dailyProduction */} +
+
+
+ +
+
Daily Production
+
+
+
+
+
+ {/* monthlyROI */} +
+
+
+ +
+
Monthly ROI
+
+
+
+
{" "} +
+
+ )} + {subModule === "simulations" && ( +
+ + {playSimulation + ? "Paused - system idle." + : "Running simulation..."} +
+ )} +
+ + + + {subModule === "analysis" && ( + + )} +
+
+
+
+
+
+ +
+
+
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 +
+
+
0.5X
+
+
+
+
+
+
+
+
+
+
+ + +
+
4x
- )} + {subModule === "analysis" && ( +
+
00:00
+
24:00
+
+
+ {process.map((item, index) => ( +
+
+
+ ))} +
+
+
+ )} +
-
+
+
+ + +
+ +
+ ); }; diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index ad24e58..dadaf9c 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -143,109 +143,109 @@ const RealTimeVisulization: React.FC = () => { }); }, [selectedZone]); - const handleDrop = async (event: React.DragEvent) => { - event.preventDefault(); - try { - const email = localStorage.getItem("email") ?? ""; - const organization = email?.split("@")[1]?.split(".")[0]; + // const handleDrop = async (event: React.DragEvent) => { + // event.preventDefault(); + // try { + // const email = localStorage.getItem("email") ?? ""; + // const organization = email?.split("@")[1]?.split(".")[0]; - const data = event.dataTransfer.getData("text/plain"); - if (widgetSubOption === "3D") return; - if (!data || selectedZone.zoneName === "") return; + // const data = event.dataTransfer.getData("text/plain"); + // if (widgetSubOption === "3D") return; + // if (!data || selectedZone.zoneName === "") return; - const droppedData = JSON.parse(data); - const canvasElement = document.getElementById("real-time-vis-canvas"); - if (!canvasElement) throw new Error("Canvas element not found"); + // const droppedData = JSON.parse(data); + // const canvasElement = document.getElementById("real-time-vis-canvas"); + // if (!canvasElement) throw new Error("Canvas element not found"); - const rect = canvasElement.getBoundingClientRect(); - const relativeX = event.clientX - rect.left; - const relativeY = event.clientY - rect.top; + // const rect = canvasElement.getBoundingClientRect(); + // const relativeX = event.clientX - rect.left; + // const relativeY = event.clientY - rect.top; - // Widget dimensions - const widgetWidth = droppedData.width ?? 125; - const widgetHeight = droppedData.height ?? 100; + // // Widget dimensions + // const widgetWidth = droppedData.width ?? 125; + // const widgetHeight = droppedData.height ?? 100; - // Center the widget at cursor - const centerOffsetX = widgetWidth / 2; - const centerOffsetY = widgetHeight / 2; + // // Center the widget at cursor + // const centerOffsetX = widgetWidth / 2; + // const centerOffsetY = widgetHeight / 2; - const adjustedX = relativeX - centerOffsetX; - const adjustedY = relativeY - centerOffsetY; + // const adjustedX = relativeX - centerOffsetX; + // const adjustedY = relativeY - centerOffsetY; - const finalPosition = determinePosition(rect, adjustedX, adjustedY); - const [activeProp1, activeProp2] = getActiveProperties(finalPosition); + // const finalPosition = determinePosition(rect, adjustedX, adjustedY); + // const [activeProp1, activeProp2] = getActiveProperties(finalPosition); - let finalY = 0; - let finalX = 0; + // let finalY = 0; + // let finalX = 0; - if (activeProp1 === "top") { - finalY = adjustedY; - } else { - finalY = rect.height - (adjustedY + widgetHeight); - } + // if (activeProp1 === "top") { + // finalY = adjustedY; + // } else { + // finalY = rect.height - (adjustedY + widgetHeight); + // } - if (activeProp2 === "left") { - finalX = adjustedX; - } else { - finalX = rect.width - (adjustedX + widgetWidth); - } + // if (activeProp2 === "left") { + // finalX = adjustedX; + // } else { + // finalX = rect.width - (adjustedX + widgetWidth); + // } - // Clamp to boundaries - finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); - finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); + // // Clamp to boundaries + // finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); + // finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); - const boundedPosition = { - ...finalPosition, - [activeProp1]: finalY, - [activeProp2]: finalX, - [activeProp1 === "top" ? "bottom" : "top"]: "auto", - [activeProp2 === "left" ? "right" : "left"]: "auto", - }; + // const boundedPosition = { + // ...finalPosition, + // [activeProp1]: finalY, + // [activeProp2]: finalX, + // [activeProp1 === "top" ? "bottom" : "top"]: "auto", + // [activeProp2 === "left" ? "right" : "left"]: "auto", + // }; - const newObject = { - ...droppedData, - id: generateUniqueId(), - position: boundedPosition, - }; + // const newObject = { + // ...droppedData, + // id: generateUniqueId(), + // position: boundedPosition, + // }; - const existingZone = - useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; - if (!existingZone) { - useDroppedObjectsStore - .getState() - .setZone(selectedZone.zoneName, selectedZone.zoneId); - } + // const existingZone = + // useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; + // if (!existingZone) { + // useDroppedObjectsStore + // .getState() + // .setZone(selectedZone.zoneName, selectedZone.zoneId); + // } - const addFloatingWidget = { - organization, - widget: newObject, - zoneId: selectedZone.zoneId, - }; + // const addFloatingWidget = { + // organization, + // widget: newObject, + // zoneId: selectedZone.zoneId, + // }; - if (visualizationSocket) { - visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); - } + // if (visualizationSocket) { + // visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); + // } - useDroppedObjectsStore - .getState() - .addObject(selectedZone.zoneName, newObject); + // useDroppedObjectsStore + // .getState() + // .addObject(selectedZone.zoneName, newObject); - const droppedObjectsStore = useDroppedObjectsStore.getState(); - const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; + // const droppedObjectsStore = useDroppedObjectsStore.getState(); + // const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; - if (currentZone && currentZone.zoneId === selectedZone.zoneId) { - console.log( - `Objects for Zone ${selectedZone.zoneId}:`, - currentZone.objects - ); - setFloatingWidget(currentZone.objects); - } else { - console.warn("Zone not found or zoneId mismatch"); - } - } catch (error) { - console.error("Error in handleDrop:", error); - } - }; + // if (currentZone && currentZone.zoneId === selectedZone.zoneId) { + // console.log( + // `Objects for Zone ${selectedZone.zoneId}:`, + // currentZone.objects + // ); + // setFloatingWidget(currentZone.objects); + // } else { + // console.warn("Zone not found or zoneId mismatch"); + // } + // } catch (error) { + // console.error("Error in handleDrop:", error); + // } + // }; useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -302,16 +302,7 @@ const RealTimeVisulization: React.FC = () => { } `} -
+
{openConfirmationPopup && ( @@ -322,20 +313,6 @@ const RealTimeVisulization: React.FC = () => { /> )} -
handleDrop(event)} - onDragOver={(event) => event.preventDefault()} - > - -
{activeModule === "visualization" && selectedZone.zoneName !== "" && ( )} diff --git a/app/src/modules/visualization/functions/handleUiDrop.ts b/app/src/modules/visualization/functions/handleUiDrop.ts new file mode 100644 index 0000000..a70742e --- /dev/null +++ b/app/src/modules/visualization/functions/handleUiDrop.ts @@ -0,0 +1,122 @@ +import { generateUniqueId } from "../../../functions/generateUniqueId"; +import { useDroppedObjectsStore } from "../../../store/visualization/useDroppedObjectsStore"; +import { determinePosition } from "./determinePosition"; +import { getActiveProperties } from "./getActiveProperties"; + +interface HandleDropProps { + widgetSubOption: any; + visualizationSocket: any; + selectedZone: any; + setFloatingWidget: (value: any) => void; + event: React.DragEvent +} + +export const createHandleDrop = ({ + widgetSubOption, + visualizationSocket, + selectedZone, + setFloatingWidget, + event, +}: HandleDropProps) => { + event.preventDefault(); + try { + const email = localStorage.getItem("email") ?? ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + const data = event.dataTransfer.getData("text/plain"); + if (widgetSubOption === "3D") return; + if (!data || selectedZone.zoneName === "") return; + + const droppedData = JSON.parse(data); + const canvasElement = document.getElementById("real-time-vis-canvas"); + if (!canvasElement) throw new Error("Canvas element not found"); + + const rect = canvasElement.getBoundingClientRect(); + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; + + // Widget dimensions + const widgetWidth = droppedData.width ?? 125; + const widgetHeight = droppedData.height ?? 100; + + // Center the widget at cursor + const centerOffsetX = widgetWidth / 2; + const centerOffsetY = widgetHeight / 2; + + const adjustedX = relativeX - centerOffsetX; + const adjustedY = relativeY - centerOffsetY; + + const finalPosition = determinePosition(rect, adjustedX, adjustedY); + const [activeProp1, activeProp2] = getActiveProperties(finalPosition); + + let finalY = 0; + let finalX = 0; + + if (activeProp1 === "top") { + finalY = adjustedY; + } else { + finalY = rect.height - (adjustedY + widgetHeight); + } + + if (activeProp2 === "left") { + finalX = adjustedX; + } else { + finalX = rect.width - (adjustedX + widgetWidth); + } + + // Clamp to boundaries + finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); + finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); + + const boundedPosition = { + ...finalPosition, + [activeProp1]: finalY, + [activeProp2]: finalX, + [activeProp1 === "top" ? "bottom" : "top"]: "auto", + [activeProp2 === "left" ? "right" : "left"]: "auto", + }; + + const newObject = { + ...droppedData, + id: generateUniqueId(), + position: boundedPosition, + }; + + const existingZone = + useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; + if (!existingZone) { + useDroppedObjectsStore + .getState() + .setZone(selectedZone.zoneName, selectedZone.zoneId); + } + + const addFloatingWidget = { + organization, + widget: newObject, + zoneId: selectedZone.zoneId, + }; + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); + } + + useDroppedObjectsStore + .getState() + .addObject(selectedZone.zoneName, newObject); + + const droppedObjectsStore = useDroppedObjectsStore.getState(); + const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; + + if (currentZone && currentZone.zoneId === selectedZone.zoneId) { + console.log( + `Objects for Zone ${selectedZone.zoneId}:`, + currentZone.objects + ); + setFloatingWidget(currentZone.objects); + } else { + console.warn("Zone not found or zoneId mismatch"); + } + } catch (error) { + console.error("Error in handleDrop:", error); + } +}; diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index bdefb8b..9bb7d0b 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -13,6 +13,7 @@ import { useWallItems, useZones, useLoadingProgress, + useWidgetSubOption, } from "../store/store"; import { useNavigate } from "react-router-dom"; import { usePlayButtonStore } from "../store/usePlayButtonStore"; @@ -22,9 +23,10 @@ import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys"; import { useSelectedUserStore } from "../store/useCollabStore"; import FollowPerson from "../components/templates/FollowPerson"; -import ProductionCapacity from "../components/ui/analysis/ProductionCapacity"; -import ThroughputSummary from "../components/ui/analysis/ThroughputSummary"; -import ROISummary from "../components/ui/analysis/ROISummary"; +import Scene from "../modules/scene/scene"; +import { createHandleDrop } from "../modules/visualization/functions/handleUiDrop"; +import { useSelectedZoneStore } from "../store/visualization/useZoneStore"; +import { useFloatingWidget } from "../store/visualization/useDroppedObjectsStore"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -53,38 +55,67 @@ const Project: React.FC = () => { } else { navigate("/"); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const { isPlaying } = usePlayButtonStore(); + // global store const { toggleThreeD } = useThreeDStore(); + + // simulation store + const { isPlaying } = usePlayButtonStore(); + + // collaboration store const { selectedUser } = useSelectedUserStore(); + // real-time visualization store + const { widgetSubOption } = useWidgetSubOption(); + const { visualizationSocket } = useSocketStore(); + const { selectedZone } = useSelectedZoneStore(); + const { setFloatingWidget } = useFloatingWidget(); + return (
- {/*
-
- - -
- -
*/} - - {loadingProgress > 0 && } - {!isPlaying && ( + {!selectedUser && ( <> - {toggleThreeD && } - - + + {loadingProgress > 0 && } + {!isPlaying && ( + <> + {toggleThreeD && } + + + + )} + + {activeModule === "market" && } + {activeModule !== "market" && } + {isPlaying && activeModule === "simulation" && } )} - {/* - - */} - {activeModule === "market" && } - - {activeModule !== "market" && } - {isPlaying && activeModule === "simulation" && } - {/* {} */} +
+ createHandleDrop({ + widgetSubOption, + visualizationSocket, + selectedZone, + setFloatingWidget, + event, + }) + } + onDragOver={(event) => event.preventDefault()} + > + +
{selectedUser && }
); diff --git a/app/src/store/visualization/useDroppedObjectsStore.ts b/app/src/store/visualization/useDroppedObjectsStore.ts index 5c4527b..bbe4cde 100644 --- a/app/src/store/visualization/useDroppedObjectsStore.ts +++ b/app/src/store/visualization/useDroppedObjectsStore.ts @@ -1,5 +1,4 @@ import { create } from "zustand"; -import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets"; import { useSocketStore } from "../store"; import useChartStore from "./useChartStore"; diff --git a/app/src/styles/base/global.scss b/app/src/styles/base/global.scss index d90e6fb..f86ba0f 100644 --- a/app/src/styles/base/global.scss +++ b/app/src/styles/base/global.scss @@ -1,11 +1,29 @@ @use "../abstracts/variables" as *; @use "../abstracts/mixins" as *; -section, .section{ - padding: 4px; - outline: 1px solid var(--border-color); - outline-offset: -1px; - border-radius: #{$border-radius-large}; - background: var(--background-color); - margin: 4px 0; +section, +.section { + padding: 4px; + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: #{$border-radius-large}; + background: var(--background-color); + margin: 4px 0; +} + +.scene-container { + width: calc(100% - (320px + 270px + 90px)); + height: calc(100% - (250px)); + position: absolute; + top: 50%; + left: calc(270px + 45px); + overflow: hidden; + z-index: 1; + transform: translate(0, -50%); + transition: all 0.2s; + box-shadow: $box-shadow-medium; + canvas { + outline: none; + border: none; + } } diff --git a/app/src/styles/base/reset.scss b/app/src/styles/base/reset.scss index ab77f9a..82d286e 100644 --- a/app/src/styles/base/reset.scss +++ b/app/src/styles/base/reset.scss @@ -12,10 +12,3 @@ input[type="password"]::-webkit-clear-button, /* For Chrome/Safari clear button input[type="password"]::-webkit-inner-spin-button { /* Just in case */ display: none; } - -button{ - border: none; - outline: none; - background: none; - cursor: pointer; -} \ No newline at end of file diff --git a/app/src/styles/components/analysis/ROISummary.scss b/app/src/styles/components/analysis/ROISummary.scss index 96b4a5d..5e2f78a 100644 --- a/app/src/styles/components/analysis/ROISummary.scss +++ b/app/src/styles/components/analysis/ROISummary.scss @@ -1,3 +1,6 @@ +@use "../../abstracts/variables" as *; +@use "../../abstracts/mixins" as *; + .roiSummary-container { .roiSummary-wrapper { background-color: var(--background-color); @@ -64,7 +67,7 @@ width: 100%; border-radius: 6px; border: 1px solid #00FF56; - background: #436D51; + background: #17eb5d65; display: flex; flex-direction: column; padding: 4px 6px; @@ -223,12 +226,11 @@ background: none; .btn { - background-color: var(--accent-color); - color: var(--background-color); - padding: 4px 6px; - border-radius: 5px; + color: var(--text-button-color); + background: var(--background-color-button); + padding: 4px 12px; + border-radius: #{$border-radius-large}; display: inline-block; - font-size: 14px; text-align: center; } } @@ -244,7 +246,6 @@ height: 250px; border-radius: 50%; position: relative; - transition: background 0.5s ease; } .progress-cover { position: absolute; @@ -252,7 +253,6 @@ height: 75%; top: 12.5%; left: 12.5%; - background: #000000cc; border-radius: 50%; } } diff --git a/app/src/styles/components/analysis/analysis.scss b/app/src/styles/components/analysis/analysis.scss index 030a79f..00a9c32 100644 --- a/app/src/styles/components/analysis/analysis.scss +++ b/app/src/styles/components/analysis/analysis.scss @@ -1,279 +1,269 @@ .analysis { - position: fixed; - top: 0; - left: 0; + position: fixed; + top: 0; + left: 0; + display: flex; + justify-content: space-between; + align-items: start; + width: 100%; + height: 100vh; + pointer-events: none; + padding: 10px; + z-index: 2; + + .analysis-wrapper { display: flex; - justify-content: space-between; - align-items: start; - width: 100%; - height: 100vh; - // pointer-events: none; - z-index: 10000; - - .analysis-wrapper { - display: flex; - flex-direction: column; - gap: 12px; - } -} - -.analysis-card { + flex-direction: column; + gap: 12px; + } + .analysis-card { min-width: 333px; background: var(--background-color); border-radius: 20px; - padding: 8px; + backdrop-filter: blur(10px); + outline: 1px solid var(--border-color); + outline-offset: -1px; + pointer-events: all; .analysis-card-wrapper { - width: 100%; - background: var(--background-color); - border-radius: 14px; - padding: 16px; + width: 100%; + 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; - gap: 14px; - .card-header { + .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: 100%; + 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%; - display: flex; - justify-content: space-between; - align-items: center; + } - .main-header { - line-height: 20px; - font-size: var(--font-size-regular); - } + .bar-fill.partial { + width: 0; // inline style will override this + } } + } - .process-container { - display: flex; - flex-direction: column; + .metrics-section { + padding-top: 16px; + border-top: 1px solid var(--background-color-gray); - .throughput-value { - font-size: 1rem; + .metric { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + margin-bottom: 8px; - .value { - font-weight: bold; - font-size: 1.5rem; - } - } + .label { + color: var(--text-color); + } - .progress-bar-wrapper { - display: flex; - gap: 8px; - margin-top: 6px; - } - - .progress-bar { - position: relative; - // width: 36px; - width: 100%; - 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; - } - } + .value { + font-weight: bold; + } } + } } -} - - -.throughoutSummary { .throughoutSummary-wrapper { - .process-container { + .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; - 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 */ + .value { + font-size: var(--font-size-xlarge); } - .lineChart { - max-width: 200px; - height: 100px; - position: relative; + .progress-wrapper { + width: 100%; + display: flex; + gap: 6px; - .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); + .progress { border-radius: 6px; - padding: 8px; + 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; - flex-direction: column; - gap: 6px; + align-items: center; + gap: 5px; - &:first-child { - width: 85%; + /* Align items vertically */ + &:nth-child(1) { + .indicator { + background: #f3c64d; + } } - .header { - font-size: var(--font-size-regular); + &:nth-child(2) { + .indicator { + background: #67b3f4; + } } - .value-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: end; - gap: 6px; + &: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%; + } + } } - - .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/button.scss b/app/src/styles/components/button.scss index e69de29..dad9120 100644 --- a/app/src/styles/components/button.scss +++ b/app/src/styles/components/button.scss @@ -0,0 +1,24 @@ +@use "../abstracts/variables" as *; +@use "../abstracts/mixins" as *; + +.labeled-button-container { + @include flex-space-between; + padding: 6px 12px; + + button { + padding: 2px 32px; + border: none; + border-radius: #{$border-radius-large}; + color: var(--text-button-color); + background: var(--background-color-button); + transition: all 0.2s; + cursor: pointer; + } +} + +button { + border: none; + outline: none; + background: none; + cursor: pointer; +} diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index e3b9585..d4c6544 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -639,21 +639,6 @@ input[type="number"] { } } -.labeled-button-container { - @include flex-space-between; - padding: 6px 12px; - - button { - padding: 2px 32px; - border: none; - border-radius: #{$border-radius-large}; - color: var(--text-button-color); - background: var(--background-color-button); - transition: all 0.2s; - cursor: pointer; - } -} - .value-field-container { margin-bottom: 6px; padding: 6px 12px; diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index 0a23871..29d37b4 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -15,7 +15,7 @@ transition: width 0.2s; background: var(--background-color); backdrop-filter: blur(8px); - z-index: #{$z-index-default}; + z-index: 2; outline: 1px solid var(--border-color); outline-offset: -1px; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index fa1b86c..319a75c 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -3,8 +3,6 @@ // Main Container .realTime-viz { - background: #131313; - box-shadow: $box-shadow-medium; width: calc(100% - (320px + 270px + 90px)); height: calc(100% - (250px)); position: absolute; @@ -12,8 +10,8 @@ left: calc(270px + 45px); transform: translate(0, -50%); border-radius: #{$border-radius-medium}; - transition: all 0.2s; - z-index: #{$z-index-default}; + z-index: 2; + pointer-events: none; .realTime-viz-wrapper { width: 100%; @@ -39,10 +37,6 @@ z-index: 1; } - .scene-container { - overflow: hidden; - } - .icon { display: flex; align-items: center; @@ -74,6 +68,8 @@ z-index: 3; transform: translate(-50%, -10%); transition: transform 0.5s linear; + pointer-events: all; + &::-webkit-scrollbar { display: none; } @@ -367,6 +363,7 @@ border-radius: 2px; transition: transform 0.3s ease; box-shadow: #{$box-shadow-medium}; + pointer-events: all; svg { stroke: var(--icon-default-color) !important; @@ -428,8 +425,6 @@ stroke: #f65648; stroke-width: 1.3; } - - } } @@ -778,17 +773,10 @@ } } - - - .panel-content { background: var(--background-color); - } - - - /* RIGHT */ .panel-content.right-opening { animation: rightExpand 0.5s ease-in-out forwards; @@ -913,9 +901,6 @@ } } - - - // Add button .extra-Bs-addopening { @@ -926,7 +911,6 @@ animation: slideUp 0.3s ease forwards; } - @keyframes slideDown { from { opacity: 0;