diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx
index 5bc3296..e3c4540 100644
--- a/app/src/components/icons/SimulationIcons.tsx
+++ b/app/src/components/icons/SimulationIcons.tsx
@@ -93,3 +93,76 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) {
);
}
+
+// simulation player icons
+
+export function ResetIcon() {
+ return (
+
+ );
+}
+
+export function PlayStopIcon() {
+ return (
+
+ );
+}
+
+export function ExitIcon() {
+ return (
+
+ );
+}
diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx
index 9d06df9..abe7ba8 100644
--- a/app/src/components/ui/Tools.tsx
+++ b/app/src/components/ui/Tools.tsx
@@ -285,9 +285,13 @@ const Tools: React.FC = () => {
>
) : (
-
setIsPlaying(false)}>
- X
-
+ <>
+ {activeModule !== "simulation" && (
+ setIsPlaying(false)}>
+ X
+
+ )}
+ >
)}
>
);
diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx
new file mode 100644
index 0000000..85f2c54
--- /dev/null
+++ b/app/src/components/ui/simulation/simulationPlayer.tsx
@@ -0,0 +1,133 @@
+import React, { useState, useRef, useEffect } from "react";
+import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons";
+import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
+
+const SimulationPlayer: React.FC = () => {
+ const [speed, setSpeed] = useState(1);
+ const [playSimulation, setPlaySimulation] = useState(false);
+ const { setIsPlaying } = usePlayButtonStore();
+ const sliderRef = useRef(null);
+ const isDragging = useRef(false);
+
+ // Button functions
+ const handleReset = () => {
+ setSpeed(1);
+ };
+ const handlePlayStop = () => {
+ setPlaySimulation(!playSimulation);
+ };
+ const handleExit = () => {
+ setPlaySimulation(false);
+ setIsPlaying(false);
+ };
+
+ // Slider functions starts
+ const handleSpeedChange = (event: React.ChangeEvent) => {
+ setSpeed(parseFloat(event.target.value));
+ };
+
+ const calculateHandlePosition = () => {
+ return ((speed - 0.5) / (50 - 0.5)) * 100;
+ };
+
+ const handleMouseDown = () => {
+ isDragging.current = true;
+ document.addEventListener("mousemove", handleMouseMove);
+ document.addEventListener("mouseup", handleMouseUp);
+ };
+
+ const handleMouseMove = (e: MouseEvent) => {
+ if (!isDragging.current || !sliderRef.current) return;
+
+ const sliderRect = sliderRef.current.getBoundingClientRect();
+ const offsetX = e.clientX - sliderRect.left;
+ const percentage = Math.min(Math.max(offsetX / sliderRect.width, 0), 1);
+ const newValue = 0.5 + percentage * (50 - 0.5);
+ setSpeed(parseFloat(newValue.toFixed(1)));
+ };
+
+ const handleMouseUp = () => {
+ isDragging.current = false;
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+ };
+
+ useEffect(() => {
+ return () => {
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+ };
+ }, []);
+ // Slider function ends
+
+ return (
+
+
+
+
{
+ handleReset();
+ }}
+ >
+
+ Reset
+
+
{
+ handlePlayStop();
+ }}
+ >
+
+ {playSimulation ? "Play" : "Stop"}
+
+
{
+ handleExit();
+ }}
+ >
+
+ Exit
+
+
+
+
0.5x
+
+
+
+
+
+
+
+
+
+
+
+
+ {speed.toFixed(1)}x
+
+
+
+
+
50x
+
+
+
+ );
+};
+
+export default SimulationPlayer;
diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx
index 95da878..ade4d6f 100644
--- a/app/src/pages/Project.tsx
+++ b/app/src/pages/Project.tsx
@@ -18,6 +18,7 @@ import { useNavigate } from "react-router-dom";
import { usePlayButtonStore } from "../store/usePlayButtonStore";
import SimulationUI from "../modules/simulation/simulationUI";
import MarketPlace from "../modules/market/MarketPlace";
+import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
const Project: React.FC = () => {
let navigate = useNavigate();
@@ -61,6 +62,7 @@ const Project: React.FC = () => {
{activeModule !== "market" && }
{/* */}
+ {isPlaying && activeModule === "simulation" && }
);
};
diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss
new file mode 100644
index 0000000..eb109c2
--- /dev/null
+++ b/app/src/styles/components/simulation/simulation.scss
@@ -0,0 +1,114 @@
+@use "../../abstracts/variables" as *;
+@use "../../abstracts/mixins" as *;
+
+.simulation-player-wrapper {
+ position: fixed;
+ bottom: 32px;
+ left: 50%;
+ z-index: 2;
+ transform: translate(-50%, 0);
+ .simulation-player-container {
+ .controls-container {
+ @include flex-center;
+ gap: 12px;
+ margin-bottom: 4px;
+ .simulation-button-container {
+ @include flex-center;
+ gap: 2px;
+ padding: 6px 8px;
+ min-width: 64px;
+ background-color: var(--background-color);
+ border-radius: #{$border-radius-small};
+ cursor: pointer;
+ &:hover {
+ background-color: 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);
+ border-radius: #{$border-radius-medium};
+ box-sizing: #{$box-shadow-medium};
+ .min-value,
+ .max-value {
+ font-weight: var(--font-weight-bold);
+ }
+ .slider-container {
+ width: 580px;
+ max-width: 80vw;
+ height: 28px;
+ background: var(--background-color-gray);
+ border-radius: #{$border-radius-small};
+ position: relative;
+ padding: 4px 26px;
+ .custom-slider {
+ height: 100%;
+ width: 100%;
+ position: relative;
+ .slider-input {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ z-index: 3;
+ cursor: pointer;
+ }
+ .slider-handle {
+ position: absolute;
+ width: 42px;
+ line-height: 20px;
+ text-align: center;
+ background: var(--accent-color);
+ color: var(--primary-color);
+ border-radius: #{$border-radius-small};
+ transform: translateX(-50%);
+ cursor: pointer;
+ z-index: 2;
+ }
+ }
+ .marker{
+ position: absolute;
+ background-color: var(--text-disabled);
+ width: 2px;
+ height: 12px;
+ border-radius: 1px;
+ top: 8px;
+ }
+ .marker.marker-10{
+ left: 10%;
+ }
+ .marker.marker-20{
+ left: 20%;
+ }
+ .marker.marker-30{
+ left: 30%;
+ }
+ .marker.marker-40{
+ left: 40%;
+ }
+ .marker.marker-50{
+ left: 50%;
+ }
+ .marker.marker-60{
+ left: 60%;
+ }
+ .marker.marker-70{
+ left: 70%;
+ }
+ .marker.marker-80{
+ left: 80%;
+ }
+ .marker.marker-90{
+ left: 90%;
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss
index fa6ce51..34c0074 100644
--- a/app/src/styles/main.scss
+++ b/app/src/styles/main.scss
@@ -20,8 +20,9 @@
@use 'components/tools';
@use 'components/visualization/floating/energyConsumed';
@use 'components/visualization/ui/styledWidgets';
-@use './components/visualization/floating/common';
-@use './components/marketPlace/marketPlace.scss';
+@use 'components/visualization/floating/common';
+@use 'components/marketPlace/marketPlace';
+@use 'components/simulation/simulation';
// layout
@use 'layout/loading';