diff --git a/app/public/index.html b/app/public/index.html index d05ca9d..22359c2 100644 --- a/app/public/index.html +++ b/app/public/index.html @@ -1,24 +1,19 @@ - - - - - - - - - - - Dwinzo (beta) - - - -
-
- - - + + + \ No newline at end of file diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index b259666..039a0a9 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -1279,3 +1279,59 @@ export const FinishEditIcon = () => { ); }; + +export const PerformanceIcon = () => { + return ( + + + + + + + + + + ); +}; + +export const GreenTickIcon = () => { + return ( + + + + + ); +}; diff --git a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx index a70c887..0f0e0da 100644 --- a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx +++ b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx @@ -115,16 +115,21 @@ const Design = () => {
- + {selectedChartId ? ( + + ) : ( + "No Preview" + )}
diff --git a/app/src/components/ui/compareVersion/Compare.tsx b/app/src/components/ui/compareVersion/Compare.tsx index f3d0b0b..93127b5 100644 --- a/app/src/components/ui/compareVersion/Compare.tsx +++ b/app/src/components/ui/compareVersion/Compare.tsx @@ -70,6 +70,7 @@ const ComparePopUp: React.FC = ({ onClose }) => { Save this version and proceed.
+ ); }; diff --git a/app/src/components/ui/compareVersion/CompareLayOut.tsx b/app/src/components/ui/compareVersion/CompareLayOut.tsx index 193dfb2..00480bc 100644 --- a/app/src/components/ui/compareVersion/CompareLayOut.tsx +++ b/app/src/components/ui/compareVersion/CompareLayOut.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from "react"; +import React, { useState, useRef, useEffect, Suspense } from "react"; import { CompareLayoutIcon, LayoutIcon, @@ -9,6 +9,7 @@ import Search from "../inputs/Search"; import OuterClick from "../../../utils/outerClick"; import RegularDropDown from "../inputs/RegularDropDown"; import { useProductStore } from "../../../store/simulation/useProductStore"; +import Scene from "../../../modules/scene/scene"; interface Layout { id: number; @@ -20,7 +21,7 @@ interface CompareLayoutProps { const CompareLayOut: React.FC = ({ dummyLayouts }) => { const { products } = useProductStore(); - console.log('products: ', products); + console.log("products: ", products); const [width, setWidth] = useState("50vw"); const [isResizing, setIsResizing] = useState(false); const [showLayoutDropdown, setShowLayoutDropdown] = useState(false); @@ -90,6 +91,7 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => { window.removeEventListener("mouseup", handleMouseUp); document.body.classList.remove("resizing-active"); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isResizing]); // Maintain proportional width on window resize @@ -120,10 +122,22 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => { ref={wrapperRef} style={{ width }} > +
-
- -
+ {selectedLayout && ( +
+ {/* + + */} +
+ )} {width !== "0px" && !selectedLayout && ( // Show only if no layout selected diff --git a/app/src/components/ui/compareVersion/ComparisonResult.tsx b/app/src/components/ui/compareVersion/ComparisonResult.tsx new file mode 100644 index 0000000..85d1c6c --- /dev/null +++ b/app/src/components/ui/compareVersion/ComparisonResult.tsx @@ -0,0 +1,133 @@ +import React, { useMemo } from "react"; +import PerformanceResult from "./result-card/PerformanceResult"; +import EnergyUsage from "./result-card/EnergyUsage"; +import { Bar } from "react-chartjs-2"; + +const ComparisonResult = () => { + const defaultData = { + labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], + datasets: [ + { + label: "Dataset", + data: [12, 19, 3, 5, 2, 3], + backgroundColor: ["#6f42c1"], + borderColor: "#b392f0", + borderWidth: 1, + }, + ], + }; + + // Memoize Chart Options + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + }, + legend: { + display: false, + }, + }, + scales: { + x: { + display: false, // Hide x-axis + grid: { + display: false, + }, + }, + y: { + display: false, // Hide y-axis + grid: { + display: false, + }, + }, + }, + }), + [] + ); + return ( +
+
Performance Comparison
+
+ +
+

Throughput (units/hr)

+
+
+
Layout 1
+
500/ hr
+
+
+
Layout 2
+
550/ hr
+
+
+
+
+
+
+
Cycle Time
+
+
+
Layout 1
+
120 Sec
+
+ 19.6% +
+
+
+
Layout 2
+
110 Sec
+
+ 19.6%1.6% +
+
+
+
+
+
+
Overall Downtime
+
+
+
+
Total down time
+
(Simulation 1)
+
+
+
17
+
mins
+
+
+
+
+
+
+
+
+
+
+ +
+
Overall Scrap Rate
+
+
+
Layout 1
+
+ Total scrap produced by +
+
2.7 ton
+
+
+ +
+
+
+ +
+
+ ); +}; + +export default ComparisonResult; diff --git a/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx b/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx new file mode 100644 index 0000000..93e80ec --- /dev/null +++ b/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx @@ -0,0 +1,108 @@ +import React, { useMemo } from "react"; +import { Line } from "react-chartjs-2"; +import { + Chart as ChartJS, + LineElement, + PointElement, + CategoryScale, + LinearScale, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + LineElement, + PointElement, + CategoryScale, + LinearScale, + Tooltip, + Legend +); + +const EnergyUsage = () => { + const data = { + labels: ["Mon", "Tue", "Wed", "Thu", "Fri"], + datasets: [ + { + label: "Simulation 1", + data: [400, 600, 450, 1000, 1000], + borderColor: "#6a0dad", + fill: false, + tension: 0.5, // More curved line + pointRadius: 0, // Remove point indicators + }, + { + label: "Simulation 2", + data: [300, 500, 700, 950, 1100], + borderColor: "#b19cd9", + fill: false, + tension: 0.5, + pointRadius: 0, + }, + ], + }; + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + }, + legend: { + display: false, + }, + }, + scales: { + x: { + display: false, // Hide x-axis + grid: { + display: false, + }, + }, + y: { + display: false, // Hide y-axis + grid: { + display: false, + }, + }, + }, + }), + [] + ); + + return ( +
+
+

Energy Usage

+

+ 2500 kWh +

+
+ +
+
+
+
+
Simulation 1
+
98%
+
+
+
+
+
+
Simulation 2
+
97%
+
+
+
+ +
+ +
+
+ ); +}; + +export default EnergyUsage; diff --git a/app/src/components/ui/compareVersion/result-card/PerformanceResult.tsx b/app/src/components/ui/compareVersion/result-card/PerformanceResult.tsx new file mode 100644 index 0000000..f21d573 --- /dev/null +++ b/app/src/components/ui/compareVersion/result-card/PerformanceResult.tsx @@ -0,0 +1,63 @@ +import React from "react"; +import { + GreenTickIcon, + PerformanceIcon, + TickIcon, +} from "../../../icons/ExportCommonIcons"; + +const PerformanceResult = () => { + return ( +
+
+
+ +
+
Performance result
+
+ +
+
+
+
+ Success rate{" "} + + + +
+
98%
+
+
Environmental impact
+
+ +
+
+
Waste generation
+
+
I
+
0.5%
+
+
+ +
+
Risk 
management
+
+
I
+
0.1%
+
+
+ +
+
+
I
+
0.5%
+
+
+
+
+ +
Simulation 1
+
+ ); +}; + +export default PerformanceResult; diff --git a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx index a0620e9..a0df039 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx @@ -197,7 +197,7 @@ const ProductionCapacity: React.FC = ({ } }, [chartMeasurements, chartDuration, widgetName]); - useEffect(() => { }, [rotation]); + useEffect(() => {}, [rotation]); return ( <> diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 3b75365..7369842 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -39,6 +39,8 @@ import RegularDropDown from "../components/ui/inputs/RegularDropDown"; import VersionSaved from "../components/layout/sidebarRight/versionHisory/VersionSaved"; import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import { useProductStore } from "../store/simulation/useProductStore"; +import ThreadChat from "../components/ui/collaboration/ThreadChat"; +import ComparisonResult from "../components/ui/compareVersion/ComparisonResult"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -179,6 +181,7 @@ const Project: React.FC = () => { />
+ {true && } )} diff --git a/app/src/styles/layout/compareLayout.scss b/app/src/styles/layout/compareLayout.scss index bee1ab8..e17f227 100644 --- a/app/src/styles/layout/compareLayout.scss +++ b/app/src/styles/layout/compareLayout.scss @@ -2,212 +2,585 @@ @use "../abstracts/mixins" as *; .initial-selectLayout-wrapper { - position: fixed; - top: 100px; - left: 40px; - z-index: 10; + position: fixed; + top: 100px; + left: 40px; + z-index: 10; - .regularDropdown-container { - background: var(--background-color); - } + .regularDropdown-container { + background: var(--background-color); + } } .compareLayOut-wrapper { - position: fixed; - top: 0; - right: 0; - z-index: 2; - height: 100vh; + position: fixed; + top: 0; + right: 0; + z-index: 2; + height: 100vh; + background: var(--background-color); + backdrop-filter: blur(20px); + display: flex; + justify-content: center; + align-items: center; + animation: slideInFromRight 0.4s ease-out forwards; + user-select: none; + + .selectLayout-wrapper { + position: absolute; + top: 100px; + right: 40px; + + .regularDropdown-container { + background: var(--background-color); + } + } + + .resizer { + width: 32px; + height: 32px; + @include flex-center; + padding: 6px; + position: absolute; + top: 50%; + left: 0; + transform: translate(-50%, -50%); background: var(--background-color); backdrop-filter: blur(20px); + box-shadow: $box-shadow-heavy; + border-radius: 50%; + cursor: ew-resize; + transition: transform 0.1s ease; + z-index: 10; + } + + .chooseLayout-container { + width: 100%; + height: 100%; display: flex; justify-content: center; align-items: center; - animation: slideInFromRight 0.4s ease-out forwards; - user-select: none; + position: relative; + overflow: hidden; - - .selectLayout-wrapper { - - position: absolute; - top: 100px; - right: 40px; - - .regularDropdown-container { - background: var(--background-color); - } + .compare-layout-canvas-container { + position: absolute; + height: 100vh; + width: 100vw; + top: 0; + right: 0; } - .chooseLayout-container { + .chooseLayout-wrapper { + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 20px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + max-width: 80%; + text-align: center; + position: relative; + + .icon { width: 100%; - height: 100%; + margin-bottom: 15px; + text-align: center; + + svg { + width: 100%; + } + } + + .value { + margin-bottom: 15px; + font-size: var(--font-size-small); + font-weight: 500; + color: var(--text-primary); + } + + button { + display: block; + margin: 0 auto; + padding: 8px 16px; + background: var(--background-color-button); + color: var(--icon-default-color-active); + border: none; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + transform: translateY(-1px); + } + } + + .displayLayouts-container { + max-width: 170px; + height: auto; + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 6px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + position: absolute; + right: 0; + top: 100%; + transform: translate(50%, -10px); display: flex; - justify-content: center; - align-items: center; - position: relative; - - .resizer { - width: 32px; - height: 32px; - @include flex-center; - padding: 6px; - position: absolute; - top: 50%; - left: 0; - transform: translate(-50%, -50%); - background: var(--background-color); - backdrop-filter: blur(20px); - box-shadow: $box-shadow-heavy; - border-radius: 50%; - cursor: ew-resize; - transition: transform 0.1s ease; - z-index: 10; - - + flex-direction: column; + gap: 6px; + .header { + text-align: left; + padding-top: 6px; + padding-left: 6px; } - .chooseLayout-wrapper { - background: var(--background-color); - backdrop-filter: blur(20px); - padding: 20px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - max-width: 80%; - text-align: center; - position: relative; + .search-wrapper { + padding: 6px 0; - .icon { - width: 100%; - margin-bottom: 15px; - text-align: center; - - svg { - - width: 100%; - } - - } - - .value { - margin-bottom: 15px; - font-size: var(--font-size-small); - font-weight: 500; - color: var(--text-primary); - } - - button { - display: block; - margin: 0 auto; - padding: 8px 16px; - background: var(--background-color-button); - color: var(--icon-default-color-active); - border: none; - border-radius: 4px; - cursor: pointer; - transition: all 0.2s ease; - - &:hover { - - transform: translateY(-1px); - } - - - - } - - .displayLayouts-container { - max-width: 170px; - height: auto; - background: var(--background-color); - backdrop-filter: blur(20px); - padding: 6px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - position: absolute; - right: 0; - top: 100%; - transform: translate(50%, -10px); - display: flex; - flex-direction: column; - gap: 6px; - - .header { - text-align: left; - padding-top: 6px; - padding-left: 6px; - } - - .search-wrapper { - padding: 6px 0; - - .search-container { - padding: 0; - border-radius: 6px; - } - } - - .layouts-container { - .layout { - - padding: 6px 0; - } - - .layout-wrapper { - display: flex; - align-items: center; - gap: 6px; - cursor: pointer; - padding: 0 10px; - background: none; - width: 100%; - - &:hover { - background-color: var(--highlight-text-color) !important; - border-radius: 4px; - - .layout { - color: var(--text-button-color) !important; - - } - - svg { - - path { - - fill: var(--text-button-color) !important; - } - } - - .layout { - - color: var(--background-color-accent); - } - } - } - } - } + .search-container { + padding: 0; + border-radius: 6px; + } } + + .layouts-container { + .layout { + padding: 6px 0; + } + + .layout-wrapper { + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; + padding: 0 10px; + background: none; + width: 100%; + + &:hover { + background-color: var(--highlight-text-color) !important; + border-radius: 4px; + + .layout { + color: var(--text-button-color) !important; + } + + svg { + path { + fill: var(--text-button-color) !important; + } + } + } + } + } + } } + } +} + +.compare-result-container { + display: flex; + flex-direction: column; + gap: 6px; + position: fixed; + bottom: 40px; + width: 100%; + min-height: 200px; + z-index: 10; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + padding: 18px 8px; + + .header { + width: fit-content; + background-color: var(--background-color-solid); + color: var(--background-color-accent); + padding: 6px 10px; + border-radius: 6px; + } + + .compare-result-wrapper { + display: flex; + gap: 12px; + + .comparisionCard { + position: relative; + flex: 1; + width: auto; + max-height: 200px; + background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: 12px; + padding: 8px 12px; + overflow: hidden; + } + + .performanceResult-wrapper { + min-width: 328px; + flex: 0; + position: relative; + padding-right: 65px; + + .header { + display: flex; + gap: 12px; + align-items: center; + } + + .metrics-container { + display: flex; + gap: 12px; + height: 100%; + + .metrics-left { + display: flex; + flex-direction: column; + justify-content: space-around; + height: 100%; + + .metric { + .metric-label { + display: flex; + align-items: center; + gap: 6px; + + span { + display: flex; + } + } + .metric-value { + padding-top: 6px; + font-size: var(--font-size-xlarge); + color: var(--background-color-accent); + font-weight: 600; + } + } + + .label { + padding-bottom: 68px; + } + } + + .metrics-right { + height: fit-content; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(2, 1fr); + + gap: 2px; + overflow: visible; + + margin: auto 0; + + .metric-wrapper { + position: relative; + width: 64px; + height: 50px; + overflow: visible; // allow content like labels to overflow + + &:nth-child(1) { + .metric-label { + top: -57%; + left: 220%; + } + &::after { + content: ""; + position: absolute; + + top: -100%; + left: 50%; + width: 100%; // Required for visible shape + height: 40px; + background-color: #b7b7c6; + + // Custom polygon shape (adjust if needed) + clip-path: polygon( + 96% 52%, + 96% 54%, + 45% 53%, + 3% 100%, + 0 100%, + 42% 52% + ); + + z-index: 0; // Behind any inner content + } + } + + // Optional: content above the shape + > * { + position: relative; + z-index: 1; + } + + &:nth-child(2) { + grid-column-start: 1; + grid-row-start: 2; + .metric-label { + white-space: normal; + width: 50px; + left: 230%; + } + } + &:nth-child(3) { + grid-row: span 2 / span 2; + grid-column-start: 2; + grid-row-start: 1; + margin-top: 40%; + left: -16px; + position: relative; + } + } + + .metric-label { + position: absolute; + top: 0px; + left: 0%; + white-space: nowrap; + + transform: translate(-50%, -50%); + + font-size: 10px; + z-index: 1; + } + + .metric { + width: 100%; + height: 100%; + position: relative; + display: flex; + justify-content: center; + align-items: center; + + &::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + background: var(--background-color, wheat); + clip-path: polygon( + 25% 0%, + 75% 0%, + 100% 50%, + 75% 100%, + 25% 100%, + 0% 50% + ); + filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); + + z-index: 0; + } + + // Content stays above the shape + > * { + position: relative; + z-index: 1; + } + } + } + } + + .simulation-tag { + background: var(--background-color-button); + + color: var(--icon-default-color-active); + position: absolute; + bottom: 0; + right: 0; + padding: 10px 5px; + border-radius: 12px 0 0 0; + } + } + } } @keyframes slideInFromRight { - from { - transform: translateX(100%); - opacity: 0; - } + from { + transform: translateX(100%); + opacity: 0; + } - to { - transform: translateX(0); - opacity: 1; - } + to { + transform: translateX(0); + opacity: 1; + } } +.energy-usage { + position: relative; -// body.compare-layout-open { -// main { -// padding-right: 10px; + .energy-usage-wrapper { + h4 { + font-weight: 600; + } -// transition: padding 0.3s ease; -// } -// } \ No newline at end of file + .value { + padding-top: 25px; + font-size: var(--font-size-xxxlarge); + color: var(--background-color-accent); + } + } + + .simulation-details { + position: absolute; + bottom: 12px; + right: 12px; + + .simulation-wrapper { + display: flex; + align-items: center; + gap: 6px; + + .icon { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: var(--background-color-accent); + } + } + } + + .chart { + width: 90%; + position: absolute; + top: 10px; + left: 0; + } +} + +.throughPutCard-container { + .layers-wrapper { + padding: 20px 10px; + height: 100%; + width: 100%; + display: flex; + justify-content: space-between; + + .layer-wrapper { + display: flex; + flex-direction: column; + + &:last-child { + justify-content: end; + } + } + } + + .chart { + height: 90%; + position: absolute; + bottom: 0; + left: 0; + } +} + +.cycle-time-container { + .cycle-main { + display: flex; + justify-content: space-between; + height: 100%; + + .layers-wrapper { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + + .layers { + display: flex; + flex-direction: column; + gap: 4px; + + .layer-name { + color: var(--background-color-accent); + } + + .layer-time { + font-size: var(--font-size-large); + } + + .layer-profit { + color: #14ca44; + text-align: end; + + span { + color: #14ca44; + } + } + } + } + } +} + +.overallDowntime-container { + .totalDownTime-wrapper { + display: flex; + + .totalDownTime { + width: 70%; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + border-radius: 12px; + + display: flex; + justify-content: space-between; + align-items: center; + gap: 20px; + padding: 8px 10px; + margin: 44px 0; + + .totalDownTime-right { + display: flex; + flex-direction: column; + gap: 6px; + } + + .totalDownTime-left { + display: flex; + align-items: center; + gap: 6px; + + .value { + font-size: var(--font-size-xlarge); + color: var(--background-color-button); + } + } + } + + .chart { + width: 30%; + position: relative; + } + } +} + +.overallScrapRate { + .overallScrapRate-wrapper { + display: flex; + + .overallScrapRate-value { + width: 50%; + display: flex; + flex-direction: column; + gap: 6px; + margin: 40px 0; + + .overallScrapRate-key { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .chart { + width: 50%; + position: relative; + } + } +} diff --git a/app/src/styles/layout/compareLayoutPopUp.scss b/app/src/styles/layout/compareLayoutPopUp.scss index 5182cb6..48820a1 100644 --- a/app/src/styles/layout/compareLayoutPopUp.scss +++ b/app/src/styles/layout/compareLayoutPopUp.scss @@ -202,6 +202,8 @@ gap: 6px; } } + + } diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 9d114e0..7c07772 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -221,7 +221,7 @@ padding: 13px 5px; background: var(--background-color-secondary); border-radius: #{$border-radius-medium}; - + box-shadow:var(--box-shadow-light); display: flex; justify-content: space-between; @@ -922,6 +922,7 @@ .display-element { width: 100%; height: 150px; + @include flex-center; background: var(--background-color); backdrop-filter: blur(20px); border-radius: 5px; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 53e3193..e8628ec 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -69,7 +69,7 @@ pointer-events: all; transition: all 0.3s linear; - &.bottom{ + &.bottom { bottom: var(--bottomWidth); } @@ -121,7 +121,8 @@ .zone-container.visualization-playing { bottom: 74px; - &.bottom{ + + &.bottom { bottom: var(--bottomWidth); } } @@ -612,7 +613,9 @@ top: 18px; right: 5px; transform: translate(0px, 0); + overflow: hidden; background: var(--background-color); + backdrop-filter: blur(20px); z-index: 10; display: flex;