Merge remote-tracking branch 'origin/v2-ui' into v2

This commit is contained in:
Jerald-Golden-B 2025-05-03 10:11:20 +05:30
commit 8b0daa3305
35 changed files with 2208 additions and 1423 deletions

View File

@ -3,23 +3,20 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Dashboard from "./pages/Dashboard";
import Project from "./pages/Project";
import UserAuth from "./pages/UserAuth";
import ToastProvider from "./components/templates/ToastProvider";
import "./styles/main.scss"
import "./styles/main.scss";
import { LoggerProvider } from "./components/ui/log/LoggerContext";
const App: React.FC = () => {
return (
<ToastProvider>
<LoggerProvider>
<Router>
<Routes>
<Route
path="/"
element={<UserAuth />}
/>
<Route path="/" element={<UserAuth />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/project" element={<Project />} />
</Routes>
</Router>
</ToastProvider>
</LoggerProvider>
);
};

View File

@ -0,0 +1,67 @@
import React from "react";
import { HelpIcon } from "../icons/DashboardIcon";
import {
LogInfoIcon,
ErrorIcon,
WarningIcon,
} from "../icons/ExportCommonIcons"; // Adjust path as needed
import { useLogger } from "../ui/log/LoggerContext";
const getLogIcon = (type: string) => {
switch (type) {
case "info":
return <LogInfoIcon />;
case "error":
return <ErrorIcon />;
case "warning":
return <WarningIcon />;
case "log":
default:
return <LogInfoIcon />;
}
};
const Footer: React.FC = () => {
const { logs, setIsLogListVisible } = useLogger();
const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
return (
<div className="footer-wrapper">
<div className="selection-wrapper">
<div className="selector-wrapper">
<div className="icon"></div>
<div className="selector">Selection</div>
</div>
<div className="selector-wrapper">
<div className="icon"></div>
<div className="selector">Rotate/Zoom</div>
</div>
<div className="selector-wrapper">
<div className="icon"></div>
<div className="selector">Pan/Context Menu</div>
</div>
</div>
<div className="logs-wrapper">
<div className="logs-detail" onClick={() => setIsLogListVisible(true)}>
{lastLog ? (
<>
<span className="log-icon">{getLogIcon(lastLog.type)}</span>
<span className="log-message">{lastLog.message}</span>
</>
) : (
"No logs yet."
)}
</div>
<div className="version">
V 0.01
<div className="icon">
<HelpIcon />
</div>
</div>
</div>
</div>
);
};
export default Footer;

View File

@ -458,7 +458,7 @@ export function InfoIcon() {
>
<path
d="M5.46289 7.75441C5.46289 7.68342 5.47691 7.6131 5.50422 7.54758C5.53158 7.48201 5.57156 7.42254 5.62201 7.37257C5.67246 7.3226 5.73231 7.2831 5.79807 7.25636C5.86388 7.22963 5.93425 7.21619 6.00529 7.21681C6.11003 7.21873 6.21188 7.25142 6.29814 7.31089C6.38435 7.37036 6.45121 7.45398 6.49019 7.55118C6.52921 7.64843 6.53862 7.75499 6.5174 7.85757C6.49614 7.96014 6.44511 8.05417 6.37071 8.12795C6.29631 8.20168 6.20185 8.25184 6.09908 8.27219C5.99631 8.29254 5.8898 8.28212 5.79294 8.24224C5.69603 8.2024 5.61308 8.13486 5.55438 8.04808C5.49567 7.96134 5.46385 7.8592 5.46289 7.75441ZM5.63564 6.44401L5.56844 3.93842C5.56206 3.87819 5.56844 3.81729 5.58716 3.75968C5.60583 3.70207 5.63641 3.64902 5.67692 3.604C5.71743 3.55897 5.76697 3.52297 5.82227 3.49832C5.87761 3.47368 5.93751 3.46094 5.99804 3.46094C6.05862 3.46094 6.11852 3.47368 6.17387 3.49832C6.22916 3.52297 6.2787 3.55897 6.31921 3.604C6.35972 3.64902 6.3903 3.70207 6.40897 3.75968C6.42769 3.81729 6.43407 3.87819 6.42769 3.93842L6.36529 6.44401C6.36529 6.54073 6.32689 6.63356 6.25844 6.70196C6.19004 6.77036 6.09721 6.80881 6.00049 6.80881C5.90372 6.80881 5.81094 6.77036 5.74254 6.70196C5.67414 6.63356 5.63564 6.54073 5.63564 6.44401Z"
fill="var(--icon-default-color)"
fill="var(--text-color)"
/>
<path
d="M6.00006 10.3175C8.45219 10.3175 10.4401 8.32963 10.4401 5.8775C10.4401 3.42536 8.45219 1.4375 6.00006 1.4375C3.54792 1.4375 1.56006 3.42536 1.56006 5.8775C1.56006 8.32963 3.54792 10.3175 6.00006 10.3175Z"
@ -471,7 +471,7 @@ export function InfoIcon() {
);
}
export function AI_Icon() {
export function AIIcon() {
return (
<svg
width="20"
@ -814,3 +814,136 @@ export const SpeedIcon = () => {
</svg>
);
};
export const LogListIcon = () => {
return (
<svg
width="24"
height="25"
viewBox="0 0 24 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 18.25H5.5M18.5 21.7272V19.3568H17.3829C16.8245 19.3568 16.375 18.9072 16.375 18.3489V18.08C16.375 17.5216 16.8246 17.0721 17.3829 17.0721H18.5V13.7318H17.2579C16.6995 13.7318 16.25 13.2822 16.25 12.7239V12.4551C16.25 11.8967 16.6996 11.4472 17.2579 11.4472H18.5V7.98185H17.2579C16.6995 7.98185 16.25 7.5323 16.25 6.97395V6.70515C16.25 6.14675 16.6996 5.69725 17.2579 5.69725H18.5V3.27065M14.5 12.75H5.5M12 7.24995H5.5M20.25 3.25H3.75C3.1977 3.25 2.75 3.6977 2.75 4.25V20.75C2.75 21.3023 3.1977 21.75 3.75 21.75H20.25C20.8023 21.75 21.25 21.3023 21.25 20.75V4.25C21.25 3.6977 20.8023 3.25 20.25 3.25Z"
stroke="#2B3344"
strokeWidth="1.2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
};
export const LogTickIcon = () => {
return (
<svg
width="10"
height="10"
viewBox="0 0 10 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_3962_4223)">
<path
d="M5.00065 0.835938C2.70482 0.835938 0.833984 2.70677 0.833984 5.0026C0.833984 7.29844 2.70482 9.16927 5.00065 9.16927C7.29648 9.16927 9.16732 7.29844 9.16732 5.0026C9.16732 2.70677 7.29648 0.835938 5.00065 0.835938ZM6.99232 4.04427L4.62982 6.40677C4.57148 6.4651 4.49232 6.49844 4.40898 6.49844C4.32565 6.49844 4.24648 6.4651 4.18815 6.40677L3.00898 5.2276C2.88815 5.10677 2.88815 4.90677 3.00898 4.78594C3.12982 4.6651 3.32982 4.6651 3.45065 4.78594L4.40898 5.74427L6.55065 3.6026C6.67148 3.48177 6.87148 3.48177 6.99232 3.6026C7.11315 3.72344 7.11315 3.91927 6.99232 4.04427Z"
fill="#49B841"
/>
</g>
<defs>
<clipPath id="clip0_3962_4223">
<rect width="10" height="10" fill="white" />
</clipPath>
</defs>
</svg>
);
};
export const LogInfoIcon = () => {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.75 2.64438V7.41438C0.75 7.92094 0.951232 8.40675 1.30943 8.76495C1.66762 9.12314 2.15344 9.32438 2.66 9.32438H3.615V10.7544L6.5 9.32438H9.365C9.87156 9.32438 10.3574 9.12314 10.7156 8.76495C11.0738 8.40675 11.275 7.92094 11.275 7.41438V2.64438C11.275 2.13781 11.0738 1.652 10.7156 1.2938C10.3574 0.935607 9.87156 0.734375 9.365 0.734375H2.66C2.15344 0.734375 1.66762 0.935607 1.30943 1.2938C0.951232 1.652 0.75 2.13781 0.75 2.64438Z"
fill="#8E8E93"
/>
<path
d="M5.04492 6.94531H6.95492"
stroke="white"
strokeWidth="0.955"
strokeMiterlimit="10"
/>
<path
d="M5.04492 4.07812H5.99992V6.94313"
stroke="white"
strokeWidth="0.955"
strokeMiterlimit="10"
/>
<path
d="M5.52539 2.65625H6.47539"
stroke="white"
strokeWidth="0.955"
strokeMiterlimit="10"
/>
</svg>
);
};
export const WarningIcon = () => {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.75 2.64438V7.41438C0.75 7.92094 0.951232 8.40675 1.30943 8.76495C1.66762 9.12314 2.15344 9.32438 2.66 9.32438H3.615V10.7544L6.5 9.32438H9.365C9.87156 9.32438 10.3574 9.12314 10.7156 8.76495C11.0738 8.40675 11.275 7.92094 11.275 7.41438V2.64438C11.275 2.13781 11.0738 1.652 10.7156 1.2938C10.3574 0.935607 9.87156 0.734375 9.365 0.734375H2.66C2.15344 0.734375 1.66762 0.935607 1.30943 1.2938C0.951232 1.652 0.75 2.13781 0.75 2.64438Z"
fill="#8E8E93"
/>
<path
d="M5.04492 6.94531H6.95492"
stroke="white"
strokeWidth="0.955"
strokeMiterlimit="10"
/>
<path
d="M5.04492 4.07812H5.99992V6.94313"
stroke="white"
strokeWidth="0.955"
strokeMiterlimit="10"
/>
<path
d="M5.52539 2.65625H6.47539"
stroke="white"
strokeWidth="0.955"
strokeMiterlimit="10"
/>
</svg>
);
};
export const ErrorIcon = () => {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M11 6C11 8.7614 8.7614 11 6 11C3.23857 11 1 8.7614 1 6C1 3.23857 3.23857 1 6 1C8.7614 1 11 3.23857 11 6ZM4.48482 4.48483C4.63126 4.33838 4.8687 4.33838 5.01515 4.48483L6 5.46965L6.9848 4.48484C7.13125 4.33839 7.3687 4.33839 7.51515 4.48484C7.6616 4.63128 7.6616 4.86872 7.51515 5.01515L6.5303 6L7.51515 6.9848C7.6616 7.13125 7.6616 7.3687 7.51515 7.51515C7.3687 7.6616 7.13125 7.6616 6.9848 7.51515L6 6.53035L5.01515 7.51515C4.86871 7.6616 4.63127 7.6616 4.48483 7.51515C4.33838 7.3687 4.33838 7.13125 4.48483 6.98485L5.46965 6L4.48482 5.01515C4.33837 4.86871 4.33837 4.63127 4.48482 4.48483Z"
fill="#ED5342"
/>
</svg>
);
};

View File

@ -125,21 +125,21 @@ export function ResetIcon() {
>
<path
d="M2.54182 4.09637C3.33333 2.73422 4.80832 1.81836 6.49721 1.81836C9.02194 1.81836 11.0686 3.86506 11.0686 6.38979C11.0686 8.91452 9.02194 10.9612 6.49721 10.9612C3.97248 10.9612 1.92578 8.91452 1.92578 6.38979"
stroke="var(--icon-default-color-active)"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7.64118 6.38895C7.64118 7.02013 7.12951 7.53181 6.49833 7.53181C5.86714 7.53181 5.35547 7.02013 5.35547 6.38895C5.35547 5.75777 5.86714 5.24609 6.49833 5.24609C7.12951 5.24609 7.64118 5.75777 7.64118 6.38895Z"
fill="var(--icon-default-color-active)"
stroke="var(--icon-default-color-active)"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.571429"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.78125 4.10407H2.49554V1.81836"
stroke="var(--icon-default-color-active)"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
@ -158,7 +158,7 @@ export function PlayStopIcon() {
>
<path
d="M8 2.88867V9.88867M11 2.88867V9.88867M2 3.99171V8.78562C2 9.28847 2 9.53987 2.09943 9.65627C2.1857 9.75732 2.31512 9.81092 2.44756 9.80047C2.60019 9.78847 2.77796 9.61072 3.13352 9.25517L5.5305 6.85817C5.69485 6.69382 5.777 6.61167 5.8078 6.51692C5.83485 6.43357 5.83485 6.34377 5.8078 6.26042C5.777 6.16567 5.69485 6.08352 5.5305 5.91917L3.13352 3.52219C2.77796 3.16664 2.60019 2.98886 2.44756 2.97685C2.31512 2.96643 2.1857 3.02004 2.09943 3.12105C2 3.23747 2 3.48888 2 3.99171Z"
stroke="var(--icon-default-color-active)"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
@ -177,7 +177,7 @@ export function ExitIcon() {
>
<path
d="M2.08203 6.34311L5.03647 3.38867M2.08203 6.34311L5.03647 9.29755M2.08203 6.34311H5.9228C7.22276 6.34334 9.34995 7.05241 10.7681 9.88867"
stroke="var(--icon-default-color-active)"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>

View File

@ -19,7 +19,7 @@ const Header: React.FC = () => {
<FileMenu />
</div>
</div>
<div
<button
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
onClick={() => {
if (activeModule !== "market") {
@ -29,7 +29,7 @@ const Header: React.FC = () => {
}}
>
<ToggleSidebarIcon />
</div>
</button>
</div>
);
};

View File

@ -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 = () => {
<div className="analysis-main-container">
<div className="header">Object</div>
<div className="generate-report-button">
<AI_Icon /> Generate Report
<AIIcon /> Generate Report
</div>
<div className="analysis-content-container section">
<div className="dropdown-header-container">
@ -121,7 +91,7 @@ const Analysis: React.FC = () => {
/>
<div className="buttons-container">
<input type="button" value={"Clear"} className="cancel" />
<input type="button" value={"Calculate"} className="submit" />
<input type="button" value={"Update"} className="submit" />
</div>
<div className="create-custom-analysis-container">
<div className="custom-analysis-header">Create Custom Analysis</div>

View File

@ -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 = () => {
<section>
<div className="header">Environment</div>
<div className="optimize-button" onClick={optimizeScene}>
<AI_Icon />
<AIIcon />
Optimize
</div>

View File

@ -18,7 +18,9 @@ const EventProperties: React.FC = () => {
const { selectedEventData } = useSelectedEventData();
const { getEventByModelUuid } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(null);
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(
null
);
const [assetType, setAssetType] = useState<string | null>(null);
const { products, addEvent } = useProductStore();
const { selectedEventSphere } = useSelectedEventSphere();
@ -89,30 +91,32 @@ const EventProperties: React.FC = () => {
<p>
<strong>Here are some products you can add it to:</strong>
</p>
<ul>
<div className="product-item">
{products.map((product) => (
<li key={product.productId}>
<button
key={product.productId}
onClick={() => {
if (selectedEventData) {
handleAddEventToProduct({
event: useEventsStore.getState().getEventByModelUuid(selectedEventData?.data.modelUuid),
event: useEventsStore
.getState()
.getEventByModelUuid(
selectedEventData?.data.modelUuid
),
addEvent,
selectedProduct,
})
});
}
}}
>
<AddIcon />
{product.productName}
</button>
</li>
))}
</ul>
</div>
</div>
)
}
</div>
)}
{!selectedEventSphere && (
<div className="no-event-selected">
<p>
@ -121,7 +125,7 @@ const EventProperties: React.FC = () => {
</p>
</div>
)}
</div >
</div>
);
};

View File

@ -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,7 +206,6 @@ const Tools: React.FC = () => {
return (
<>
{!isPlaying ? (
<>
<div className="tools-container">
<div className="drop-down-icons">
<div className="activeDropicon">
@ -464,13 +460,12 @@ const Tools: React.FC = () => {
</>
)}
</div>
</>
) : (
<>
{activeModule !== "simulation" && (
<div className="exitPlay" onClick={() => setIsPlaying(false)}>
<button className="exitPlay" onClick={() => setIsPlaying(false)}>
X
</div>
</button>
)}
</>
)}

View File

@ -1,6 +1,7 @@
import React, { useState } from "react";
import { ROISummaryIcon } from "../../icons/analysis";
import SemiCircleProgress from "./SemiCircleProgress";
import { ArrowIcon } from "../../icons/ExportCommonIcons";
const ROISummary = ({
roiSummaryData = {
@ -121,7 +122,7 @@ const ROISummary = ({
</div>
<span className={`expand-icon ${isTableOpen ? "open" : ""}`}>
{isTableOpen ? "⌵" : "⌵"}
<ArrowIcon />
</span>
</div>
<div

View File

@ -0,0 +1,95 @@
// LogList.tsx
import React, { useState } from "react";
import {
LogListIcon,
LogInfoIcon,
WarningIcon,
ErrorIcon,
CloseIcon,
} from "../../icons/ExportCommonIcons"; // Adjust path as needed
import { useLogger } from "./LoggerContext";
const LogList: React.FC = () => {
const { logs, clear, setIsLogListVisible } = useLogger();
const [selectedTab, setSelectedTab] = useState<
"all" | "info" | "warning" | "error" | "log"
>("all");
const getLogIcon = (type: string) => {
switch (type) {
case "info":
return <LogInfoIcon />;
case "error":
return <ErrorIcon />;
case "warning":
return <WarningIcon />;
case "log":
default:
return <LogInfoIcon />;
}
};
const formatTimestamp = (date: Date) => new Date(date).toLocaleTimeString();
const filteredLogs =
selectedTab === "all"
? [...logs].reverse()
: [...logs].filter((log) => log.type === selectedTab).reverse();
return (
// eslint-disable-next-line
<div
className="log-list-container"
onClick={() => setIsLogListVisible(false)}
>
<div
className="log-list-wrapper"
onClick={(e) => {
e.stopPropagation();
}}
>
<div className="log-header">
<div className="log-header-wrapper">
<div className="icon">
<LogListIcon />
</div>
<div className="head">Log List</div>
</div>
<button className="close" onClick={() => setIsLogListVisible(false)}>
<CloseIcon />
</button>
</div>
{/* Tabs */}
<div className="log-nav-wrapper">
{["all", "info", "warning", "error"].map((type) => (
<div
key={type}
className={`log-nav ${selectedTab === type ? "active" : ""}`}
onClick={() => setSelectedTab(type as any)}
>
{`${type.charAt(0).toUpperCase() + type.slice(1)} Logs`}
</div>
))}
</div>
{/* Log Entries */}
<div className="log-entry-wrapper">
{filteredLogs.map((log) => (
<div key={log.id} className={`log-entry ${log.type}`}>
<div className="log-icon">{getLogIcon(log.type)}</div>
<div className="log-entry-message-container">
<div className="log-entry-message">{log.message}</div>
<div className="message-time">
{formatTimestamp(log.timestamp)}
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
};
export default LogList;

View File

@ -0,0 +1,77 @@
import React, { createContext, useContext, useState, useCallback } from "react";
export type LogType = "log" | "info" | "warning" | "error";
export interface LogEntry {
id: string;
type: LogType;
message: string;
timestamp: Date;
}
interface LoggerContextValue {
logs: LogEntry[];
setLogs: React.Dispatch<React.SetStateAction<LogEntry[]>>;
isLogListVisible: boolean;
setIsLogListVisible: React.Dispatch<React.SetStateAction<boolean>>;
log: (message: string) => void;
info: (message: string) => void;
warn: (message: string) => void;
error: (message: string) => void;
clear: () => void;
}
const LoggerContext = createContext<LoggerContextValue | undefined>(undefined);
export const LoggerProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [logs, setLogs] = useState<LogEntry[]>([]);
const [isLogListVisible, setIsLogListVisible] = useState<boolean>(false);
const generateId = useCallback(
() => Math.random().toString(36).substring(2, 9),
[]
);
const addLog = useCallback(
(type: LogType, message: string) => {
const newLog: LogEntry = {
id: generateId(),
type,
message,
timestamp: new Date(),
};
setLogs((prevLogs) => [...prevLogs, newLog]);
},
[generateId]
);
const loggerMethods: LoggerContextValue = {
logs,
setLogs,
isLogListVisible,
setIsLogListVisible,
log: (message: string) => addLog("log", message),
info: (message: string) => addLog("info", message),
warn: (message: string) => addLog("warning", message),
error: (message: string) => addLog("error", message),
clear: () => {
setLogs([]);
},
};
return (
<LoggerContext.Provider value={loggerMethods}>
{children}
</LoggerContext.Provider>
);
};
export const useLogger = () => {
const context = useContext(LoggerContext);
if (!context) {
throw new Error("useLogger must be used within a LoggerProvider");
}
return context;
};

View File

@ -0,0 +1,71 @@
type LogType = 'log' | 'info' | 'warning' | 'error';
interface LogEntry {
type: LogType;
message: string;
timestamp: Date;
context?: string;
}
class Logger {
private static instance: Logger;
private logs: LogEntry[] = [];
private subscribers: Array<(log: LogEntry) => void> = [];
private constructor() {}
public static getInstance(): Logger {
if (!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}
private notifySubscribers(log: LogEntry) {
this.subscribers.forEach(callback => callback(log));
}
private addLog(type: LogType, message: string, context?: string) {
const log: LogEntry = { type, message, timestamp: new Date(), context };
this.logs.push(log);
this.notifySubscribers(log);
if (process.env.NODE_ENV === 'development') {
const logMessage = context ? `[${context}] ${message}` : message;
console[type === 'warning' ? 'warn' : type](logMessage);
}
}
public log(message: string, context?: string) {
this.addLog('log', message, context);
}
public info(message: string, context?: string) {
this.addLog('info', message, context);
}
public warning(message: string, context?: string) {
this.addLog('warning', message, context);
}
public error(message: string, context?: string) {
this.addLog('error', message, context);
}
public getLogs(): LogEntry[] {
return [...this.logs];
}
public clear() {
this.logs = [];
}
public subscribe(callback: (log: LogEntry) => void) {
this.subscribers.push(callback);
return () => {
this.subscribers = this.subscribers.filter(sub => sub !== callback);
};
}
}
export const logger = Logger.getInstance();

View File

@ -12,25 +12,31 @@ import {
EndIcon,
ExpandIcon,
HourlySimulationIcon,
InfoIcon,
MonthlyROI,
SpeedIcon,
StartIcon,
} 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
const isDragging = useRef(false);
const sliderRef = useRef<HTMLDivElement>(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<HTMLDivElement>(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 +120,7 @@ const SimulationPlayer: React.FC = () => {
};
// Store colors for each process item
const [processColors, setProcessColors] = useState<string[]>([]);
const [_, setProcessColors] = useState<string[]>([]);
// Generate colors on mount or when process changes
useEffect(() => {
@ -159,9 +165,11 @@ const SimulationPlayer: React.FC = () => {
};
return (
<>
<div className="simulation-player-wrapper">
<div className={`simulation-player-container ${expand ? "open" : ""}`}>
<div className="controls-container">
{subModule === "analysis" && (
<div className="production-details">
{/* hourlySimulation */}
<div className="hourly-wrapper production-wrapper">
@ -202,10 +210,22 @@ const SimulationPlayer: React.FC = () => {
<div className="label">Monthly ROI</div>
</div>
<div className="progress-wrapper">
<div className="progress" style={{ width: monthlyROI }}></div>
<div
className="progress"
style={{ width: monthlyROI }}
></div>
</div>{" "}
</div>
</div>
)}
{subModule === "simulations" && (
<div className="header">
<InfoIcon />
{playSimulation
? "Paused - system idle."
: "Running simulation..."}
</div>
)}
<div className="controls-wrapper">
<button
className="simulation-button-container"
@ -234,12 +254,14 @@ const SimulationPlayer: React.FC = () => {
<ExitIcon />
Exit
</button>
{subModule === "analysis" && (
<button
className="expand-icon-container"
onClick={() => setExpand(!expand)}
>
<ExpandIcon isActive={!expand} />
</button>
)}
</div>
</div>
<div className="progresser-wrapper">
@ -330,6 +352,7 @@ const SimulationPlayer: React.FC = () => {
</div>
</div>
</div>
{subModule === "analysis" && (
<div className="processDisplayer">
<div className="start-displayer timmer">00:00</div>
<div className="end-displayer timmer">24:00</div>
@ -361,8 +384,17 @@ const SimulationPlayer: React.FC = () => {
</div>
</div>
</div>
)}
</div>
</div>
<div className="analysis">
<div className="analysis-wrapper">
<ProductionCapacity />
<ThroughputSummary />
</div>
<ROISummary />
</div>
</>
);
};

View File

@ -142,109 +142,109 @@ const RealTimeVisulization: React.FC = () => {
});
}, [selectedZone]);
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
try {
const email = localStorage.getItem("email") ?? "";
const organization = email?.split("@")[1]?.split(".")[0];
// const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
// 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) => {
@ -301,16 +301,7 @@ const RealTimeVisulization: React.FC = () => {
}
`}
</style>
<div
ref={containerRef}
id="real-time-vis-canvas"
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
}}
>
<div ref={containerRef} className="realTime-viz">
<div className="realTime-viz-wrapper">
{openConfirmationPopup && (
<RenderOverlay>
@ -321,20 +312,6 @@ const RealTimeVisulization: React.FC = () => {
/>
</RenderOverlay>
)}
<div
className="scene-container"
style={{
height: "100%",
width: "100%",
borderRadius:
isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
role="application"
onDrop={(event) => handleDrop(event)}
onDragOver={(event) => event.preventDefault()}
>
<Scene />
</div>
{activeModule === "visualization" && selectedZone.zoneName !== "" && (
<DroppedObjects />
)}

View File

@ -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<HTMLDivElement>
}
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);
}
};

View File

@ -13,6 +13,7 @@ import {
useWallItems,
useZones,
useLoadingProgress,
useWidgetSubOption,
} from "../store/store";
import { useNavigate } from "react-router-dom";
import { usePlayButtonStore } from "../store/usePlayButtonStore";
@ -22,12 +23,19 @@ 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";
import { useLogger } from "../components/ui/log/LoggerContext";
import RenderOverlay from "../components/templates/Overlay";
import LogList from "../components/ui/log/LogList";
import Footer from "../components/footer/Footer";
const Project: React.FC = () => {
let navigate = useNavigate();
const echo = useLogger();
const { activeModule, setActiveModule } = useModuleStore();
const { loadingProgress } = useLoadingProgress();
const { setUserName } = useUserName();
@ -50,24 +58,33 @@ const Project: React.FC = () => {
setOrganization(Organization);
setUserName(name);
}
echo.info("Log in success full");
} 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();
const { isLogListVisible } = useLogger();
// real-time visualization store
const { widgetSubOption } = useWidgetSubOption();
const { visualizationSocket } = useSocketStore();
const { selectedZone } = useSelectedZoneStore();
const { setFloatingWidget } = useFloatingWidget();
return (
<div className="project-main">
{/* <div className="analysis">
<div className="analysis-wrapper">
<ProductionCapacity />
<ThroughputSummary />
</div>
<ROISummary />
</div> */}
{!selectedUser && (
<>
<KeyPressListener />
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
{!isPlaying && (
@ -77,15 +94,43 @@ const Project: React.FC = () => {
<SideBarRight />
</>
)}
{/* <RenderOverlay>
<MenuBar setOpenMenu={setOpenMenu} />
</RenderOverlay> */}
{activeModule === "market" && <MarketPlace />}
<RealTimeVisulization />
{activeModule === "market" && <MarketPlace />}
{activeModule !== "market" && <Tools />}
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
{/* {<SimulationPlayer />} */}
</>
)}
<div
className="scene-container"
id="real-time-vis-canvas"
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
borderRadius:
isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
role="application"
onDrop={(event) =>
createHandleDrop({
widgetSubOption,
visualizationSocket,
selectedZone,
setFloatingWidget,
event,
})
}
onDragOver={(event) => event.preventDefault()}
>
<Scene />
</div>
{selectedUser && <FollowPerson />}
{isLogListVisible && (
<RenderOverlay>
<LogList />
</RenderOverlay>
)}
<Footer />
</div>
);
};

View File

@ -1,5 +1,4 @@
import { create } from "zustand";
import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets";
import { useSocketStore } from "../store";
import useChartStore from "./useChartStore";

View File

@ -22,7 +22,11 @@ $text-button-color-dark: #f3f3fd;
// background colors
// ---------- light mode ----------
$background-color: linear-gradient(-45deg, #fcfdfd71 0%, #fcfdfd79 100%);
$background-color-solid-gradient: linear-gradient(-45deg, #fcfdfd 0%, #fcfdfd 100%);
$background-color-solid-gradient: linear-gradient(
-45deg,
#fcfdfd 0%,
#fcfdfd 100%
);
$background-color-solid: #fcfdfd;
$background-color-secondary: #fcfdfd4d;
$background-color-accent: #6f42c1;
@ -45,7 +49,11 @@ $background-radial-gray-gradient: radial-gradient(
// ---------- dark mode ----------
$background-color-dark: linear-gradient(-45deg, #333333b3 0%, #2d2437b3 100%);
$background-color-solid-gradient-dark: linear-gradient(-45deg, #333333 0%, #2d2437 100%);
$background-color-solid-gradient-dark: linear-gradient(
-45deg,
#333333 0%,
#2d2437 100%
);
$background-color-solid-dark: #19191d;
$background-color-secondary-dark: #19191d99;
$background-color-accent-dark: #6f42c1;
@ -104,6 +112,21 @@ $color3: #b186ff;
$color4: #8752e8;
$color5: #c7a8ff;
// log indication colors
// ------------ text -------------
$log-default-text-color: #6f42c1;
$log-info-text-color: #488ef6;
$log-warn-text-color: #f3a50c;
$log-error-text-color: #f65648;
$log-success-text-color: #43c06d;
// ------------ background -------------
$log-default-backgroung-color: #6e42c133;
$log-info-background-color: #488ef633;
$log-warn-background-color: #f3a50c33;
$log-error-background-color: #f6564833;
$log-success-background-color: #43c06d33;
// old variables
$accent-color: #6f42c1;
$accent-color-dark: #c4abf1;

View File

@ -37,11 +37,9 @@
// old colors
--accent-color: #{$accent-color};
--highlight-accent-color: #{$highlight-accent-color};
--accent-gradient-color: #{$acent-gradient};
--faint-gradient-color: #{$faint-gradient};
--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);
@ -75,7 +73,7 @@
--background-radial-gray-gradient: #{$background-radial-gray-gradient-dark};
// border colors
--border-color: #{$border-color};
--border-color: #{$border-color-dark};
--input-border-color: #{$input-border-color-dark};
--border-color-accent: #{$border-color-accent-dark};
@ -89,11 +87,9 @@
// 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-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);

View File

@ -1,7 +1,8 @@
@use "../abstracts/variables" as *;
@use "../abstracts/mixins" as *;
section, .section{
section,
.section {
padding: 4px;
outline: 1px solid var(--border-color);
outline-offset: -1px;
@ -9,3 +10,21 @@ section, .section{
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;
background: var(--background-color-solid);
canvas {
outline: none;
border: none;
}
}

View File

@ -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;
}

View File

@ -1,311 +0,0 @@
.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: #000000cc;
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;
}
}
}

View File

@ -1,279 +0,0 @@
.analysis {
position: fixed;
top: 0;
left: 0;
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 {
min-width: 333px;
background: var(--background-color);
border-radius: 20px;
padding: 8px;
.analysis-card-wrapper {
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;
.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;
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;
}
}
}
}
}
.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%;
}
}
}
}
}
}
}
}

View File

@ -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;
}

View File

@ -0,0 +1,71 @@
@use "../../abstracts/variables" as *;
@use "../../abstracts/mixins" as *;
.footer-wrapper {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 1;
display: flex;
justify-content: space-between;
padding: 2px 12px;
.selection-wrapper {
display: flex;
gap: 6px;
.selector-wrapper {
display: flex;
gap: 6px;
align-items: center;
background: var(--background-color);
padding: 3px 6px;
border-radius: 12px;
color: var(--text-color);
.selector {
color: var(--text-color);
}
}
}
.logs-wrapper {
display: flex;
gap: 6px;
.logs-detail,
.version {
border-radius: 12px;
background: var(--background-color);
padding: 3px 6px;
color: var(--text-color);
display: flex;
align-items: center;
gap: 6px;
}
.logs-detail {
padding: 2px 12px;
cursor: pointer;
.log-icon {
@include flex-center;
}
.log-message {
max-width: 40vw;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.version {
font-size: var(--font-size-tiny);
display: flex;
gap: 6px;
.icon{
@include flex-center;
}
}
}
}

View File

@ -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;

View File

@ -0,0 +1,105 @@
@use "../../abstracts/variables" as *;
@use "../../abstracts/mixins" as *;
.log-list-container {
width: 100vw;
height: 100vh;
background: var(--background-color-secondary);
.log-list-wrapper {
height: 50%;
min-width: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 5;
background: var(--background-color);
padding: 14px 12px;
border-radius: 15px;
display: flex;
flex-direction: column;
gap: 12px;
backdrop-filter: blur(50px);
outline: 1px solid var(--border-color);
.log-header {
display: flex;
justify-content: space-between;
.log-header-wrapper {
display: flex;
align-items: center;
gap: 6px;
}
.close {
@include flex-center;
height: 28px;
width: 28px;
cursor: pointer;
svg {
scale: 1.6;
}
}
}
.log-nav-wrapper {
display: flex;
gap: 6px;
.log-nav {
padding: 8px 16px;
border-radius: 19px;
}
.log-nav.active {
background-color: var(--background-color-accent);
color: var(--text-button-color);
}
}
.log-entry-wrapper {
height: 100%;
display: flex;
flex-direction: column;
gap: 4px;
background: var(--background-color);
padding: 18px 10px;
border-radius: 16px;
outline: 1px solid var(--border-color);
outline-offset: -1px;
.log-entry {
padding: 4px;
border-radius: 4px;
font-size: var(--font-size-small);
display: flex;
align-items: center;
gap: 6px;
.log-icon {
@include flex-center;
}
.log-entry-message-container {
@include flex-space-between;
gap: 12px;
width: 100%;
.message-time {
font-size: var(--font-size-tiny);
font-weight: 300;
opacity: 0.8;
text-wrap: nowrap;
}
.log-entry-message{
width: 100%;
}
}
&:nth-child(odd) {
background: var(--background-color);
}
}
}
}
}

View File

@ -0,0 +1,557 @@
@use "../../abstracts/variables" as *;
@use "../../abstracts/mixins" as *;
.analysis {
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;
flex-direction: column;
gap: 12px;
}
.analysis-card {
min-width: 333px;
border-radius: 20px;
padding: 8px;
pointer-events: all;
.analysis-card-wrapper {
width: 100%;
background: var(--background-color);
border-radius: 14px;
padding: 16px;
display: flex;
flex-direction: column;
gap: 14px;
backdrop-filter: blur(10px);
outline: 1px solid var(--border-color);
outline-offset: -1px;
.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: 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;
}
}
}
}
.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%;
}
}
}
}
}
}
}
}
.roiSummary-wrapper {
max-width: 470px;
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: #{$border-radius-xxx};
border: 1px solid #00ff56;
background: #17eb5e42;
display: flex;
flex-direction: column;
padding: 4px 8px;
&:last-child {
align-items: center;
}
.metric-label {
opacity: 0.8;
font-size: 10px;
font-weight: 300;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.metric-value {
text-align: center;
line-height: 20px;
}
}
.metric-wrapper {
display: flex;
gap: 6px;
.metric-item {
border-radius: #{$border-radius-large};
background-color: var(--background-color);
border: 1px solid var(--border-color);
}
}
}
}
.cost-breakdown {
background-color: var(--background-color);
border: 1px solid var(--border-color);
border-radius: #{$border-radius-extra-large};
padding: 16px;
.breakdown-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
.section-wrapper {
display: flex;
gap: 4px;
align-items: center;
}
.section-number {
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;
overflow: hidden;
outline: 1px solid var(--border-color);
outline-offset: -1px;
margin-top: 12px;
th,
td {
color: var(--text-color);
padding: 8px;
text-align: left;
border: 1px solid var(--border-color);
}
th {
background-color: var(--background-color);
}
}
}
.tips-section {
background-color: var(--background-color);
border-radius: #{$border-radius-large};
outline: 1px solid var(--border-color);
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 {
color: var(--text-button-color);
background: var(--background-color-button);
padding: 4px 12px;
border-radius: #{$border-radius-large};
display: inline-block;
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;
}
.progress-cover {
position: absolute;
width: 75%;
height: 75%;
top: 12.5%;
left: 12.5%;
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-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;
}
}
}
// Breakdown Table Open/Close Logic

View File

@ -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;
}
@ -307,6 +314,22 @@
font-size: var(--font-size-tiny);
}
.timmer {
width: auto;
position: absolute;
bottom: 0;
font-size: var(--font-size-tiny);
}
.start-displayer {
left: 8px;
}
.end-displayer {
width: auto;
right: 8px;
}
.start-displayer {
bottom: 4px;
left: 16px;
@ -347,6 +370,12 @@
}
.simulation-player-container.open {
.start-displayer,
.end-displayer {
display: none;
}
.timmer {
display: none;
}

View File

@ -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;
@ -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;

View File

@ -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);
}
}
}
@ -420,7 +416,7 @@
outline: none;
path {
stroke: var(--text-button-color);
stroke-width: 1.3;
strokeWidth: 1.3;
}
}
}
@ -686,7 +682,7 @@
path {
stroke: var(--accent-color);
stroke-width: 1.5px;
strokeWidth: 1.5px;
}
&:hover {
@ -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%;

View File

@ -13,7 +13,6 @@
@use 'components/button';
@use 'components/form';
@use 'components/input';
@use 'components/layouts';
@use 'components/lists';
@use 'components/moduleToggle';
@use 'components/templates';
@ -22,11 +21,12 @@
@use 'components/visualization/ui/styledWidgets';
@use 'components/visualization/floating/common';
@use 'components/marketPlace/marketPlace';
@use 'components/simulation/simulation';
@use 'components/menu/menu';
@use 'components/confirmationPopUp';
@use 'components/analysis/analysis';
@use 'components/analysis/ROISummary.scss';
@use 'components/simulation/simulation';
@use 'components/simulation/analysis';
@use 'components/logs/logs';
@use 'components/footer/footer.scss';
// layout
@use 'layout/loading';

View File

@ -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;
@ -426,10 +423,8 @@
path {
stroke: #f65648;
stroke-width: 1.3;
strokeWidth: 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;