This commit is contained in:
Nalvazhuthi
2025-05-13 16:54:37 +05:30
29 changed files with 622 additions and 478 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,9 +1,6 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Search from "../../ui/inputs/Search"; import Search from "../../ui/inputs/Search";
import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets/getCategoryAsset"; import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets/getCategoryAsset";
import arch from "../../../assets/gltf-glb/arch.glb";
import door from "../../../assets/gltf-glb/door.glb";
import window from "../../../assets/gltf-glb/window.glb";
import { fetchAssets } from "../../../services/marketplace/fetchAssets"; import { fetchAssets } from "../../../services/marketplace/fetchAssets";
import { useSelectedItem } from "../../../store/store"; import { useSelectedItem } from "../../../store/store";
@@ -16,8 +13,6 @@ import storage from "../../../assets/image/categories/storage.png";
import office from "../../../assets/image/categories/office.png"; import office from "../../../assets/image/categories/office.png";
import safety from "../../../assets/image/categories/safety.png"; import safety from "../../../assets/image/categories/safety.png";
import feneration from "../../../assets/image/categories/feneration.png"; import feneration from "../../../assets/image/categories/feneration.png";
import archThumbnail from "../../../assets/image/localAssets/arch.png";
import windowThumbnail from "../../../assets/image/localAssets/window.png";
import SkeletonUI from "../../templates/SkeletonUI"; import SkeletonUI from "../../templates/SkeletonUI";
// ------------------------------------- // -------------------------------------
@@ -90,24 +85,7 @@ const Assets: React.FC = () => {
useEffect(() => { useEffect(() => {
setCategoryList([ setCategoryList([
{ { category: "Fenestration", categoryImage: feneration },
assetName: "Doors",
assetImage: "",
category: "Feneration",
categoryImage: feneration,
},
{
assetName: "Windows",
assetImage: "",
category: "Feneration",
categoryImage: feneration,
},
{
assetName: "Pillars",
assetImage: "",
category: "Feneration",
categoryImage: feneration,
},
{ category: "Vehicles", categoryImage: vehicle }, { category: "Vehicles", categoryImage: vehicle },
{ category: "Workstation", categoryImage: workStation }, { category: "Workstation", categoryImage: workStation },
{ category: "Machines", categoryImage: machines }, { category: "Machines", categoryImage: machines },
@@ -121,44 +99,15 @@ const Assets: React.FC = () => {
const fetchCategoryAssets = async (asset: any) => { const fetchCategoryAssets = async (asset: any) => {
setisLoading(true); setisLoading(true);
setSelectedCategory(asset); setSelectedCategory(asset);
if (asset === "Feneration") { try {
const localAssets: AssetProp[] = [ const res = await getCategoryAsset(asset);
{ setCategoryAssets(res);
filename: "arch", setFiltereredAssets(res);
category: "Feneration", setisLoading(false); // End loading
url: arch, // eslint-disable-next-line
thumbnail: archThumbnail, } catch (error) {
tags: "arch", echo.error("failed to fetch assets");
},
{
filename: "door",
category: "Feneration",
url: door,
thumbnail: feneration,
tags: "door",
},
{
filename: "window",
category: "Feneration",
url: window,
thumbnail: windowThumbnail,
tags: "window",
},
];
setCategoryAssets(localAssets);
setFiltereredAssets(localAssets);
setisLoading(false); setisLoading(false);
} else {
try {
const res = await getCategoryAsset(asset);
setCategoryAssets(res);
setFiltereredAssets(res);
setisLoading(false); // End loading
// eslint-disable-next-line
} catch (error) {
echo.error("failed to fetch assets");
setisLoading(false);
}
} }
}; };
@@ -167,64 +116,21 @@ const Assets: React.FC = () => {
<Search onChange={handleSearchChange} /> <Search onChange={handleSearchChange} />
<div className="assets-list-section"> <div className="assets-list-section">
<section> <section>
{isLoading ? ( {(() => {
<SkeletonUI type="asset" /> // Show skeleton when loading if (isLoading) {
) : searchValue ? ( return <SkeletonUI type="asset" />; // Show skeleton when loading
<div className="assets-result"> }
<div className="assets-wrapper"> if (searchValue) {
<div className="searched-content"> return (
<p>Results for {searchValue}</p> <div className="assets-result">
</div> <div className="assets-wrapper">
<div className="assets-container"> <div className="searched-content">
{categoryAssets?.map((asset: any, index: number) => ( <p>Results for {searchValue}</p>
<div
key={index}
className="assets"
id={asset.filename}
title={asset.filename}
>
<img
src={asset?.thumbnail}
alt={asset.filename}
className="asset-image"
/>
<div className="asset-name">
{asset.filename
.split("_")
.map(
(word: any) =>
word.charAt(0).toUpperCase() + word.slice(1)
)
.join(" ")}
</div>
</div> </div>
))} <div className="assets-container">
</div> {categoryAssets?.map((asset: any, index: number) => (
</div>
</div>
) : (
<>
{selectedCategory ? (
<div className="assets-wrapper">
<h2>
{selectedCategory}{" "}
<div
className="back-button"
id="asset-backButtom"
onClick={() => {
setSelectedCategory(null);
setCategoryAssets([]);
}}
>
Back
</div>
</h2>
<div className="assets-container">
{categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
<div <div
key={index} key={`${index}-${asset.filename}`}
className="assets" className="assets"
id={asset.filename} id={asset.filename}
title={asset.filename} title={asset.filename}
@@ -233,17 +139,8 @@ const Assets: React.FC = () => {
src={asset?.thumbnail} src={asset?.thumbnail}
alt={asset.filename} alt={asset.filename}
className="asset-image" className="asset-image"
onPointerDown={() => {
setSelectedItem({
name: asset.filename,
id: asset.AssetID,
type:
asset.type === "undefined"
? undefined
: asset.type,
});
}}
/> />
<div className="asset-name"> <div className="asset-name">
{asset.filename {asset.filename
.split("_") .split("_")
@@ -255,40 +152,104 @@ const Assets: React.FC = () => {
</div> </div>
</div> </div>
))} ))}
</div>
</div> </div>
</div> </div>
) : ( );
}
if (selectedCategory) {
return (
<div className="assets-wrapper"> <div className="assets-wrapper">
<h2>Categories</h2> <h2>
<div className="categories-container"> {selectedCategory}
{Array.from( <button
new Set(categoryList.map((asset) => asset.category)) className="back-button"
).map((category, index) => { id="asset-backButtom"
const categoryInfo = categoryList.find( onClick={() => {
(asset) => asset.category === category setSelectedCategory(null);
); setCategoryAssets([]);
return ( }}
<div >
key={index} Back
className="category" </button>
id={category} </h2>
onClick={() => fetchCategoryAssets(category)} <div className="assets-container">
> {categoryAssets?.map((asset: any, index: number) => (
<img <div
src={categoryInfo?.categoryImage || ""} key={`${index}-${asset}`}
alt={category} className="assets"
className="category-image" id={asset.filename}
draggable={false} title={asset.filename}
/> >
<div className="category-name">{category}</div> <img
src={asset?.thumbnail}
alt={asset.filename}
className="asset-image"
onPointerDown={() => {
setSelectedItem({
name: asset.filename,
id: asset.AssetID,
type:
asset.type === "undefined"
? undefined
: asset.type,
});
}}
/>
<div className="asset-name">
{asset.filename
.split("_")
.map(
(word: any) =>
word.charAt(0).toUpperCase() + word.slice(1)
)
.join(" ")}
</div> </div>
); </div>
})} ))}
{categoryAssets.length === 0 && (
<div className="no-asset">
🚧 The asset shelf is empty. We're working on filling it
up!
</div>
)}
</div> </div>
</div> </div>
)} );
</> }
)}
return (
<div className="assets-wrapper">
<h2>Categories</h2>
<div className="categories-container">
{Array.from(
new Set(categoryList.map((asset) => asset.category))
).map((category, index) => {
const categoryInfo = categoryList.find(
(asset) => asset.category === category
);
return (
<button
key={`${index}-${category}`}
className="category"
id={category}
onClick={() => fetchCategoryAssets(category)}
>
<img
src={categoryInfo?.categoryImage ?? ""}
alt={category}
className="category-image"
draggable={false}
/>
<div className="category-name">{category}</div>
</button>
);
})}
</div>
</div>
);
})()}
</section> </section>
</div> </div>
</div> </div>

View File

@@ -6,7 +6,7 @@ import useToggleStore from "../../../store/useUIToggleStore";
import useModuleStore from "../../../store/useModuleStore"; import useModuleStore from "../../../store/useModuleStore";
const Header: React.FC = () => { const Header: React.FC = () => {
const { toggleUI, setToggleUI } = useToggleStore(); const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
return ( return (
@@ -20,15 +20,17 @@ const Header: React.FC = () => {
</div> </div>
</div> </div>
<button <button
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`} className={`toggle-sidebar-ui-button ${!toggleUILeft ? "active" : ""}`}
onClick={() => { onClick={() => {
if (activeModule !== "market") { if (activeModule !== "market") {
setToggleUI(!toggleUI); setToggleUI(!toggleUILeft, toggleUIRight);
localStorage.setItem("navBarUi", JSON.stringify(!toggleUI)); localStorage.setItem("navBarUiLeft", JSON.stringify(!toggleUILeft));
} }
}} }}
> >
<div className="tooltip">{toggleUI ? "Hide" : "Show"} sidebar (ctrl + \)</div> <div className="tooltip">
{toggleUILeft ? "Hide" : "Show"} sidebar (ctrl + [)
</div>
<ToggleSidebarIcon /> <ToggleSidebarIcon />
</button> </button>
</div> </div>

View File

@@ -12,7 +12,7 @@ import Search from "../../ui/inputs/Search";
const SideBarLeft: React.FC = () => { const SideBarLeft: React.FC = () => {
const [activeOption, setActiveOption] = useState("Widgets"); const [activeOption, setActiveOption] = useState("Widgets");
const { toggleUI } = useToggleStore(); const { toggleUILeft } = useToggleStore();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
// Reset activeOption whenever activeModule changes // Reset activeOption whenever activeModule changes
@@ -31,47 +31,55 @@ const SideBarLeft: React.FC = () => {
}; };
return ( return (
<div className={`sidebar-left-wrapper ${toggleUI ? "open" : "closed"}`}> <div className={`sidebar-left-wrapper ${toggleUILeft ? "open" : "closed"}`}>
<Header /> <Header />
{toggleUI && ( {toggleUILeft && (
<div className={`sidebar-left-container `}> <div className={`sidebar-left-container `}>
{activeModule === "visualization" ? ( {(() => {
<> if (activeModule === "visualization") {
<ToggleHeader return (
options={["Widgets", "Templates"]} <>
activeOption={activeOption} <ToggleHeader
handleClick={handleToggleClick} options={["Widgets", "Templates"]}
/> activeOption={activeOption}
<Search onChange={handleSearchChange} /> handleClick={handleToggleClick}
<div className="sidebar-left-content-container"> />
{activeOption === "Widgets" ? <Widgets /> : <Templates />} <Search onChange={handleSearchChange} />
</div> <div className="sidebar-left-content-container">
</> {activeOption === "Widgets" ? <Widgets /> : <Templates />}
) : activeModule === "market" ? ( </div>
<></> </>
) : activeModule === "builder" ? ( );
<> } else if (activeModule === "market") {
<ToggleHeader return <></>;
options={["Outline", "Assets"]} } else if (activeModule === "builder") {
activeOption={activeOption} return (
handleClick={handleToggleClick} <>
/> <ToggleHeader
<div className="sidebar-left-content-container"> options={["Outline", "Assets"]}
{activeOption === "Outline" ? <Outline /> : <Assets />} activeOption={activeOption}
</div> handleClick={handleToggleClick}
</> />
) : ( <div className="sidebar-left-content-container">
<> {activeOption === "Outline" ? <Outline /> : <Assets />}
<ToggleHeader </div>
options={["Outline"]} </>
activeOption={activeOption} );
handleClick={handleToggleClick} } else {
/> return (
<div className="sidebar-left-content-container"> <>
{activeOption === "Outline" ? <Outline /> : <Assets />} <ToggleHeader
</div> options={["Outline"]}
</> activeOption={activeOption}
)} handleClick={handleToggleClick}
/>
<div className="sidebar-left-content-container">
{activeOption === "Outline" ? <Outline /> : <Assets />}
</div>
</>
);
}
})()}
</div> </div>
)} )}
</div> </div>

View File

@@ -5,10 +5,15 @@ import { ActiveUser } from "../../../types/users";
import CollaborationPopup from "../../templates/CollaborationPopup"; import CollaborationPopup from "../../templates/CollaborationPopup";
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
import { useSelectedUserStore } from "../../../store/useCollabStore"; import { useSelectedUserStore } from "../../../store/useCollabStore";
import useToggleStore from "../../../store/useUIToggleStore";
import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
import useModuleStore from "../../../store/useModuleStore";
const Header: React.FC = () => { const Header: React.FC = () => {
const { activeUsers } = useActiveUsers(); const { activeUsers } = useActiveUsers();
const userName = localStorage.getItem("userName") ?? "Anonymous"; const userName = localStorage.getItem("userName") ?? "Anonymous";
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
const { activeModule } = useModuleStore();
const guestUsers: ActiveUser[] = activeUsers.filter( const guestUsers: ActiveUser[] = activeUsers.filter(
(user: ActiveUser) => user.userName !== userName (user: ActiveUser) => user.userName !== userName
@@ -55,6 +60,25 @@ const Header: React.FC = () => {
)} )}
<div className="header-container"> <div className="header-container">
<div className="options-container"> <div className="options-container">
<button
className={`toggle-sidebar-ui-button ${
!toggleUIRight ? "active" : ""
}`}
onClick={() => {
if (activeModule !== "market") {
setToggleUI(toggleUILeft, !toggleUIRight);
localStorage.setItem(
"navBarUiRight",
JSON.stringify(!toggleUIRight)
);
}
}}
>
<div className="tooltip">
{toggleUIRight ? "Hide" : "Show"} sidebar (ctrl + ])
</div>
<ToggleSidebarIcon />
</button>
<button <button
className="share-button" className="share-button"
onClick={() => { onClick={() => {

View File

@@ -28,7 +28,7 @@ import VersionHistory from "./versionHisory/VersionHistory";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { toggleUI } = useToggleStore(); const { toggleUIRight } = useToggleStore();
const { subModule, setSubModule } = useSubModuleStore(); const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem(); const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
@@ -59,9 +59,9 @@ const SideBarRight: React.FC = () => {
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]); }, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
return ( return (
<div className={`sidebar-right-wrapper ${toggleUI ? "open" : "closed"}`}> <div className={`sidebar-right-wrapper ${toggleUIRight ? "open" : "closed"}`}>
<Header /> <Header />
{toggleUI && ( {toggleUIRight && (
<div className="sidebar-actions-container"> <div className="sidebar-actions-container">
{activeModule !== "simulation" && ( {activeModule !== "simulation" && (
<button <button
@@ -120,7 +120,7 @@ const SideBarRight: React.FC = () => {
</div> </div>
)} )}
{toggleUI && viewVersionHistory && ( {toggleUIRight && viewVersionHistory && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<VersionHistory /> <VersionHistory />
@@ -129,7 +129,7 @@ const SideBarRight: React.FC = () => {
)} )}
{/* process builder */} {/* process builder */}
{toggleUI && {toggleUIRight &&
!viewVersionHistory && !viewVersionHistory &&
subModule === "properties" && subModule === "properties" &&
activeModule !== "visualization" && activeModule !== "visualization" &&
@@ -140,7 +140,7 @@ const SideBarRight: React.FC = () => {
</div> </div>
</div> </div>
)} )}
{toggleUI && {toggleUIRight &&
!viewVersionHistory && !viewVersionHistory &&
subModule === "properties" && subModule === "properties" &&
activeModule !== "visualization" && activeModule !== "visualization" &&
@@ -152,7 +152,7 @@ const SideBarRight: React.FC = () => {
</div> </div>
)} )}
{toggleUI && {toggleUIRight &&
!viewVersionHistory && !viewVersionHistory &&
subModule === "zoneProperties" && subModule === "zoneProperties" &&
(activeModule === "builder" || activeModule === "simulation") && ( (activeModule === "builder" || activeModule === "simulation") && (
@@ -163,7 +163,7 @@ const SideBarRight: React.FC = () => {
</div> </div>
)} )}
{/* simulation */} {/* simulation */}
{toggleUI && !viewVersionHistory && activeModule === "simulation" && ( {toggleUIRight && !viewVersionHistory && activeModule === "simulation" && (
<> <>
{subModule === "simulations" && ( {subModule === "simulations" && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
@@ -189,7 +189,7 @@ const SideBarRight: React.FC = () => {
</> </>
)} )}
{/* realtime visualization */} {/* realtime visualization */}
{toggleUI && activeModule === "visualization" && <Visualization />} {toggleUIRight && activeModule === "visualization" && <Visualization />}
</div> </div>
); );
}; };

View File

@@ -7,7 +7,6 @@ interface SkeletonUIProps {
// Define the SkeletonUI component // Define the SkeletonUI component
const SkeletonUI: React.FC<SkeletonUIProps> = ({ type }) => { const SkeletonUI: React.FC<SkeletonUIProps> = ({ type }) => {
// Function to render skeleton content based on 'type' // Function to render skeleton content based on 'type'
const renderSkeleton = () => { const renderSkeleton = () => {
switch (type) { switch (type) {
@@ -38,17 +37,28 @@ const SkeletonUI: React.FC<SkeletonUIProps> = ({ type }) => {
case "asset": case "asset":
return ( return (
<> <>
<div className="skeleton-content"> <div className="skeleton asset-category-title"></div>
<div className="skeleton asset-name"></div> <div className="skeleton-content-asset">
<div className="skeleton asset"></div> <div className="skeleton-content">
</div> <div className="skeleton asset-name"></div>
<div className="skeleton-content"> <div className="skeleton asset"></div>
<div className="skeleton asset-name"></div> </div>
<div className="skeleton asset"></div> <div className="skeleton-content">
<div className="skeleton asset-name"></div>
<div className="skeleton asset"></div>
</div>
<div className="skeleton-content">
<div className="skeleton asset-name"></div>
<div className="skeleton asset"></div>
</div>
<div className="skeleton-content">
<div className="skeleton asset-name"></div>
<div className="skeleton asset"></div>
</div>
</div> </div>
</> </>
); );
default: default:
return ( return (
<div className="skeleton-content"> <div className="skeleton-content">

View File

@@ -32,7 +32,7 @@ const FileMenu: React.FC = () => {
}, []); }, []);
// project // project
const [projectName, setProjectName] = useState("project 1"); const [projectName, setProjectName] = useState("Demo Project");
// Load project name from localStorage on mount // Load project name from localStorage on mount
useEffect(() => { useEffect(() => {

View File

@@ -22,8 +22,11 @@ const ModuleToggle: React.FC = () => {
setActiveModule("builder"); setActiveModule("builder");
setVersionHistory(false); setVersionHistory(false);
setToggleUI( setToggleUI(
localStorage.getItem("navBarUi") localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUi") === "true" ? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true : true
); );
}} }}
@@ -41,8 +44,11 @@ const ModuleToggle: React.FC = () => {
setActiveModule("simulation"); setActiveModule("simulation");
setVersionHistory(false); setVersionHistory(false);
setToggleUI( setToggleUI(
localStorage.getItem("navBarUi") localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUi") === "true" ? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true : true
); );
}} }}
@@ -60,8 +66,11 @@ const ModuleToggle: React.FC = () => {
setActiveModule("visualization"); setActiveModule("visualization");
setVersionHistory(false); setVersionHistory(false);
setToggleUI( setToggleUI(
localStorage.getItem("navBarUi") localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUi") === "true" ? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true : true
); );
}} }}
@@ -76,7 +85,7 @@ const ModuleToggle: React.FC = () => {
onClick={() => { onClick={() => {
setActiveModule("market"); setActiveModule("market");
setVersionHistory(false); setVersionHistory(false);
setToggleUI(false); setToggleUI(false, false);
}} }}
> >
<div className="icon"> <div className="icon">

View File

@@ -71,8 +71,11 @@ const Tools: React.FC = () => {
// Reset activeTool whenever activeModule changes // Reset activeTool whenever activeModule changes
useEffect(() => { useEffect(() => {
setToggleUI( setToggleUI(
localStorage.getItem("navBarUi") localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUi") === "true" ? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true : true
); );
}, []); }, []);
@@ -93,8 +96,11 @@ const Tools: React.FC = () => {
setToggleView(false); setToggleView(false);
} }
setToggleUI( setToggleUI(
localStorage.getItem("navBarUi") localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUi") === "true" ? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true : true
); );
setToggleThreeD(!toggleThreeD); setToggleThreeD(!toggleThreeD);
@@ -119,7 +125,7 @@ const Tools: React.FC = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!toggleThreeD) { if (!toggleThreeD) {
setToggleUI(false); setToggleUI(false, false);
} }
}, [toggleThreeD]); }, [toggleThreeD]);

View File

@@ -205,7 +205,7 @@ const ROISummary = ({
</table> </table>
</div> </div>
</div> </div>
<div className="tips-section"> {/* <div className="tips-section">
<div className="tip-header"> <div className="tip-header">
<span className="lightbulb-icon"> <span className="lightbulb-icon">
<LightBulpIcon /> <LightBulpIcon />
@@ -224,7 +224,7 @@ const ROISummary = ({
<button className="get-tips-button"> <button className="get-tips-button">
<div className="btn">Get ROI Boost Tips</div> <div className="btn">Get ROI Boost Tips</div>
</button> </button>
</div> </div> */}
</> </>
) : ( ) : (
<SkeletonUI type={"default"} /> <SkeletonUI type={"default"} />

View File

@@ -5,7 +5,7 @@ import SkeletonUI from "../../templates/SkeletonUI";
const ProductionCapacity = ({ const ProductionCapacity = ({
progressPercent = 50, progressPercent = 50,
avgProcessTime = "28.4 Secs/unit", avgProcessTime = "28.4",
machineUtilization = "78%", machineUtilization = "78%",
throughputValue = 128, throughputValue = 128,
timeRange = { startTime: "08:00 AM", endTime: "09:00 AM" }, timeRange = { startTime: "08:00 AM", endTime: "09:00 AM" },
@@ -34,7 +34,7 @@ const ProductionCapacity = ({
<> <>
<div className="process-container"> <div className="process-container">
<div className="throughput-value"> <div className="throughput-value">
<span className="value">{throughputValue}</span> Units/hour <span className="value">{avgProcessTime}</span> secs/unit
</div> </div>
{/* Dynamic Progress Bar */} {/* Dynamic Progress Bar */}
@@ -56,8 +56,8 @@ const ProductionCapacity = ({
<div className="metrics-section"> <div className="metrics-section">
<div className="metric"> <div className="metric">
<span className="label">Avg. Process Time</span> <span className="label">Units/hour</span>
<span className="value">{avgProcessTime}</span> <span className="value">{throughputValue} avg.</span>
</div> </div>
<div className="metric"> <div className="metric">
<span className="label">Machine Utilization</span> <span className="label">Machine Utilization</span>

View File

@@ -2,6 +2,7 @@ import React, { useState } from "react";
import { ArrowIcon } from "../../icons/ExportCommonIcons"; import { ArrowIcon } from "../../icons/ExportCommonIcons";
import { toggleTheme } from "../../../utils/theme"; import { toggleTheme } from "../../../utils/theme";
import useVersionHistoryStore, { useShortcutStore } from "../../../store/store"; import useVersionHistoryStore, { useShortcutStore } from "../../../store/store";
import { useNavigate } from "react-router-dom";
import { useSubModuleStore } from "../../../store/useModuleStore"; import { useSubModuleStore } from "../../../store/useModuleStore";
interface MenuBarProps { interface MenuBarProps {
@@ -9,6 +10,7 @@ interface MenuBarProps {
} }
const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => { const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
const navigate = useNavigate();
const [activeMenu, setActiveMenu] = useState<string | null>(null); const [activeMenu, setActiveMenu] = useState<string | null>(null);
const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null); const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null);
@@ -36,6 +38,12 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
const savedTheme: string | null = localStorage.getItem("theme") ?? "light"; const savedTheme: string | null = localStorage.getItem("theme") ?? "light";
const handleLogout = () => {
localStorage.clear(); // 1. Clear all localStorage
navigate('/'); // 2. Redirect to homepage
};
return ( return (
<div <div
className="menu-bar" className="menu-bar"
@@ -552,6 +560,9 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
</div> </div>
)} )}
</div> </div>
<div className="menu-button-container" onClick={handleLogout}>
<div className="menu-button">Log out</div>
</div>
</div> </div>
</div> </div>
); );

View File

@@ -2,8 +2,8 @@ import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from "../../../../types/world/worldConstants"; import * as CONSTANTS from "../../../../types/world/worldConstants";
import texturePath from "../../../../assets/textures/floor/concreteFloorWorn001Diff2k.jpg"; import texturePath from "../../../../assets/textures/floor/white.png";
import normalPath from "../../../../assets/textures/floor/concreteFloorWorn001NorGl2k.jpg"; import texturePathDark from "../../../../assets/textures/floor/black.png";
// Cache for materials // Cache for materials
const materialCache = new Map<string, THREE.Material>(); const materialCache = new Map<string, THREE.Material>();
@@ -14,6 +14,8 @@ export default function addFloorToScene(
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
userData: any, userData: any,
) { ) {
const savedTheme: string | null = localStorage.getItem('theme');
const textureLoader = new THREE.TextureLoader(); const textureLoader = new THREE.TextureLoader();
const textureScale = CONSTANTS.floorConfig.textureScale; const textureScale = CONSTANTS.floorConfig.textureScale;
@@ -24,20 +26,17 @@ export default function addFloorToScene(
if (materialCache.has(materialKey)) { if (materialCache.has(materialKey)) {
material = materialCache.get(materialKey) as THREE.Material; material = materialCache.get(materialKey) as THREE.Material;
// } else {
} else { } else {
const floorTexture = textureLoader.load(texturePath); const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath);
const normalMap = textureLoader.load(normalPath); // const floorTexture = textureLoader.load(texturePath);
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping; floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(textureScale, textureScale); floorTexture.repeat.set(textureScale, textureScale);
floorTexture.colorSpace = THREE.SRGBColorSpace; floorTexture.colorSpace = THREE.SRGBColorSpace;
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
normalMap.repeat.set(textureScale, textureScale);
material = new THREE.MeshStandardMaterial({ material = new THREE.MeshStandardMaterial({
map: floorTexture, map: floorTexture,
normalMap: normalMap,
side: THREE.DoubleSide, side: THREE.DoubleSide,
}); });

View File

@@ -1,7 +1,6 @@
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { import {
useActiveTool, useActiveTool,
useAsset3dWidget,
useCamMode, useCamMode,
useDeletableFloorItem, useDeletableFloorItem,
useDeleteTool, useDeleteTool,
@@ -14,7 +13,6 @@ import {
useToggleView, useToggleView,
useTransformMode, useTransformMode,
} from "../../../store/store"; } from "../../../store/store";
import assetVisibility from "../geomentries/assets/assetVisibility";
import { useEffect } from "react"; import { useEffect } from "react";
import * as THREE from "three"; import * as THREE from "three";
import * as Types from "../../../types/world/worldTypes"; import * as Types from "../../../types/world/worldTypes";
@@ -29,7 +27,6 @@ import loadInitialFloorItems from "../IntialLoad/loadInitialFloorItems";
import addAssetModel from "../geomentries/assets/addAssetModel"; import addAssetModel from "../geomentries/assets/addAssetModel";
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
import useModuleStore from "../../../store/useModuleStore"; import useModuleStore from "../../../store/useModuleStore";
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
import { useEventsStore } from "../../../store/simulation/useEventsStore"; import { useEventsStore } from "../../../store/simulation/useEventsStore";
const assetManagerWorker = new Worker( const assetManagerWorker = new Worker(
@@ -198,9 +195,7 @@ const FloorItemsGroup = ({
}; };
const startInterval = () => { const startInterval = () => {
if (!intervalId) { intervalId ??= setInterval(handleChange, 50);
intervalId = setInterval(handleChange, 50);
}
}; };
const stopInterval = () => { const stopInterval = () => {

View File

@@ -1,56 +1,92 @@
import { Geometry } from "@react-three/csg"; import { Geometry } from "@react-three/csg";
import { useDeleteTool, useSelectedWallItem, useToggleView, useTransformMode, useWallItems, useWalls } from "../../../store/store"; import {
useDeleteTool,
useSelectedWallItem,
useToggleView,
useTransformMode,
useWallItems,
useWalls,
} from "../../../store/store";
import handleMeshDown from "../eventFunctions/handleMeshDown"; import handleMeshDown from "../eventFunctions/handleMeshDown";
import handleMeshMissed from "../eventFunctions/handleMeshMissed"; import handleMeshMissed from "../eventFunctions/handleMeshMissed";
import WallsMesh from "./wallsMesh"; import WallsMesh from "./wallsMesh";
import WallItemsGroup from "./wallItemsGroup"; import WallItemsGroup from "./wallItemsGroup";
import { useEffect } from "react"; import { useEffect } from "react";
const WallsAndWallItems = ({
CSGGroup,
AssetConfigurations,
setSelectedItemsIndex,
selectedItemsIndex,
currentWallItem,
csg,
lines,
hoveredDeletableWallItem,
}: any) => {
const { walls } = useWalls();
const { wallItems } = useWallItems();
const { toggleView } = useToggleView();
const { deleteTool } = useDeleteTool();
const { transformMode } = useTransformMode();
const { setSelectedWallItem } = useSelectedWallItem();
const WallsAndWallItems = ({ CSGGroup, AssetConfigurations, setSelectedItemsIndex, selectedItemsIndex, currentWallItem, csg, lines, hoveredDeletableWallItem }: any) => { useEffect(() => {
const { walls, setWalls } = useWalls(); if (transformMode === null) {
const { wallItems, setWallItems } = useWallItems(); if (!deleteTool) {
const { toggleView, setToggleView } = useToggleView(); handleMeshMissed(
const { deleteTool, setDeleteTool } = useDeleteTool(); currentWallItem,
const { transformMode, setTransformMode } = useTransformMode(); setSelectedWallItem,
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); setSelectedItemsIndex
);
useEffect(() => { setSelectedWallItem(null);
if (transformMode === null) { setSelectedItemsIndex(null);
if (!deleteTool) { }
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex); }
setSelectedWallItem(null); }, [transformMode]);
setSelectedItemsIndex(null); return (
} <mesh
ref={CSGGroup as any}
name="Walls"
key={walls.length}
receiveShadow
visible={!toggleView}
onClick={(event) => {
if (!deleteTool && transformMode !== null) {
handleMeshDown(
event,
currentWallItem,
setSelectedWallItem,
setSelectedItemsIndex,
wallItems,
toggleView
);
} }
}, [transformMode]) }}
onPointerMissed={() => {
if (!deleteTool) {
handleMeshMissed(
currentWallItem,
setSelectedWallItem,
setSelectedItemsIndex
);
setSelectedWallItem(null);
setSelectedItemsIndex(null);
}
}}
>
<Geometry ref={csg as any} computeVertexNormals useGroups>
<WallsMesh lines={lines} />
<WallItemsGroup
currentWallItem={currentWallItem}
AssetConfigurations={AssetConfigurations}
hoveredDeletableWallItem={hoveredDeletableWallItem}
selectedItemsIndex={selectedItemsIndex}
setSelectedItemsIndex={setSelectedItemsIndex}
CSGGroup={CSGGroup}
/>
</Geometry>
</mesh>
);
};
return ( export default WallsAndWallItems;
<mesh
ref={CSGGroup as any}
name="Walls"
key={walls.length}
receiveShadow
visible={!toggleView}
onClick={(event) => {
if (!deleteTool && transformMode !== null) {
handleMeshDown(event, currentWallItem, setSelectedWallItem, setSelectedItemsIndex, wallItems, toggleView);
}
}}
onPointerMissed={() => {
if (!deleteTool) {
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
setSelectedWallItem(null);
setSelectedItemsIndex(null);
}
}}
>
<Geometry ref={csg as any} computeVertexNormals useGroups>
<WallsMesh lines={lines} />
<WallItemsGroup currentWallItem={currentWallItem} AssetConfigurations={AssetConfigurations} hoveredDeletableWallItem={hoveredDeletableWallItem} selectedItemsIndex={selectedItemsIndex} setSelectedItemsIndex={setSelectedItemsIndex} CSGGroup={CSGGroup} />
</Geometry>
</mesh>
)
}
export default WallsAndWallItems;

View File

@@ -1,65 +1,78 @@
import * as THREE from 'three'; import * as THREE from "three";
import * as Types from '../../../types/world/worldTypes'; import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from '../../../types/world/worldConstants'; import * as CONSTANTS from "../../../types/world/worldConstants";
import { Base } from '@react-three/csg'; import { Base } from "@react-three/csg";
import { MeshDiscardMaterial } from '@react-three/drei'; import { MeshDiscardMaterial } from "@react-three/drei";
import { useUpdateScene, useWalls } from '../../../store/store'; import { useUpdateScene, useWalls } from "../../../store/store";
import { useEffect } from 'react'; import React, { useEffect } from "react";
import { getLines } from '../../../services/factoryBuilder/lines/getLinesApi'; import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
import objectLinesToArray from '../geomentries/lines/lineConvertions/objectLinesToArray'; import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
import loadWalls from '../geomentries/walls/loadWalls'; import loadWalls from "../geomentries/walls/loadWalls";
// texture
import texturePath from "../../../assets/textures/floor/wall-tex.png";
const WallsMesh = ({ lines }: any) => { // Cache for materials
const { walls, setWalls } = useWalls(); const materialCache = new Map<string, THREE.Material>();
const { updateScene, setUpdateScene } = useUpdateScene();
useEffect(() => { const WallsMeshComponent = ({ lines }: any) => {
if (updateScene) { const { walls, setWalls } = useWalls();
const { updateScene, setUpdateScene } = useUpdateScene();
const email = localStorage.getItem('email') useEffect(() => {
const organization = (email!.split("@")[1]).split(".")[0]; if (updateScene) {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
getLines(organization).then((data) => { getLines(organization).then((data) => {
const Lines: Types.Lines = objectLinesToArray(data); const Lines: Types.Lines = objectLinesToArray(data);
localStorage.setItem("Lines", JSON.stringify(Lines)); localStorage.setItem("Lines", JSON.stringify(Lines));
if (Lines) { if (Lines) {
loadWalls(lines, setWalls); loadWalls(lines, setWalls);
}
})
setUpdateScene(false);
} }
}, [updateScene]) });
setUpdateScene(false);
}
}, [updateScene]);
return ( const textureLoader = new THREE.TextureLoader();
<> const wallTexture = textureLoader.load(texturePath);
{walls.map((wall: Types.Wall, index: number) => (
<mesh key={index}>
<Base
name={`Wall${index + 1}`}
geometry={wall[0]}
rotation={wall[1]}
position={wall[2]}
userData={{ WallType: wall[3], Layer: wall[4] }}
>
<meshStandardMaterial
side={THREE.DoubleSide}
color={CONSTANTS.wallConfig.defaultColor}
/>
</Base>
<mesh
castShadow
geometry={wall[0]}
rotation={wall[1]}
position={wall[2]}
name={`WallRaycastReference_${index + 1}`}
>
<MeshDiscardMaterial />
</mesh>
</mesh>
))}
</>
)
}
export default WallsMesh; wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
wallTexture.repeat.set(0.1, 0.1);
wallTexture.colorSpace = THREE.SRGBColorSpace;
return (
<>
{walls.map((wall: Types.Wall, index: number) => (
<mesh key={index} renderOrder={1}>
<Base
name={`Wall${index + 1}`}
geometry={wall[0]}
rotation={wall[1]}
position={wall[2]}
userData={{ WallType: wall[3], Layer: wall[4] }}
>
<meshStandardMaterial
side={THREE.DoubleSide}
color={CONSTANTS.wallConfig.defaultColor}
map={wallTexture}
/>
</Base>
<mesh
castShadow
geometry={wall[0]}
rotation={wall[1]}
position={wall[2]}
name={`WallRaycastReference_${index + 1}`}
>
<MeshDiscardMaterial />
</mesh>
</mesh>
))}
</>
);
};
const WallsMesh = React.memo(WallsMeshComponent);
export default WallsMesh;

View File

@@ -49,7 +49,7 @@ function MoveControls({
"Ctrl" | "Shift" | "Ctrl+Shift" | "" "Ctrl" | "Shift" | "Ctrl+Shift" | ""
>(""); >("");
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0]; const organization = email?.split("@")[1].split(".")[0] ?? null;
const updateBackend = ( const updateBackend = (
productName: string, productName: string,
@@ -308,7 +308,7 @@ function MoveControls({
} }
); );
if (event) { if (event && organization) {
updateBackend( updateBackend(
selectedProduct.productName, selectedProduct.productName,
selectedProduct.productId, selectedProduct.productId,

View File

@@ -22,7 +22,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
const itemsData = useRef<Types.FloorItems>([]); const itemsData = useRef<Types.FloorItems>([]);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email?.split("@")[1])?.split(".")[0] ?? null;
const updateBackend = ( const updateBackend = (
productName: string, productName: string,
@@ -214,7 +214,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
}) })
if (event) { if (event && organization) {
updateBackend( updateBackend(
selectedProduct.productName, selectedProduct.productName,
selectedProduct.productId, selectedProduct.productId,

View File

@@ -187,6 +187,7 @@ const RealTimeVisulization: React.FC = () => {
<div <div
ref={containerRef} ref={containerRef}
className="realTime-viz" className="realTime-viz"
id="real-time-vis-canvas"
style={{ style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "", height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "", width: isPlaying || activeModule !== "visualization" ? "100vw" : "",

View File

@@ -1,13 +1,17 @@
import { create } from "zustand"; import { create } from "zustand";
interface ToggleState { interface ToggleState {
toggleUI: boolean; // State to track UI toggle toggleUILeft: boolean;
setToggleUI: (value: boolean) => void; // Action to update toggleUI toggleUIRight: boolean;
setToggleUI: (value1: boolean, value2: boolean) => void;
} }
const useToggleStore = create<ToggleState>((set) => ({ const useToggleStore = create<ToggleState>((set) => ({
toggleUI: true, // Initial state toggleUILeft: true,
setToggleUI: (value: boolean) => set({ toggleUI: value }), // Update the state toggleUIRight: false,
setToggleUI: (value1: boolean, value2: boolean) => {
set({ toggleUILeft: value1, toggleUIRight: value2 });
},
})); }));
export default useToggleStore; export default useToggleStore;

View File

@@ -1,6 +1,55 @@
@use "../abstracts/variables" as *; @use "../abstracts/variables" as *;
@use "../abstracts/mixins" as *; @use "../abstracts/mixins" as *;
.toggle-sidebar-ui-button {
@include flex-center;
cursor: pointer;
height: 32px;
width: 32px;
min-height: 32px;
min-width: 32px;
border-radius: #{$border-radius-large};
position: relative;
.tooltip {
top: 6px;
right: -168px;
&::after {
left: 0px;
bottom: 50%;
}
}
&:hover {
outline: 1px solid var(--border-color);
outline-offset: -1px;
background: var(--background-color-solid);
.tooltip {
opacity: 1;
transform: translateX(2px);
}
}
}
.toggle-sidebar-ui-button.active {
background: var(--background-color-accent);
rect {
stroke: var(--icon-default-color-active);
}
circle {
fill: var(--icon-default-color-active);
}
&:hover {
filter: saturate(0.8);
background: var(--background-color-accent);
}
}
.sidebar-left-wrapper { .sidebar-left-wrapper {
width: 270px; width: 270px;
position: fixed; position: fixed;
@@ -34,15 +83,6 @@
} }
.toggle-sidebar-ui-button { .toggle-sidebar-ui-button {
@include flex-center;
cursor: pointer;
height: 32px;
width: 32px;
min-height: 32px;
min-width: 32px;
border-radius: #{$border-radius-large};
position: relative;
.tooltip { .tooltip {
top: 6px; top: 6px;
right: -168px; right: -168px;
@@ -52,34 +92,6 @@
bottom: 50%; bottom: 50%;
} }
} }
&:hover {
outline: 1px solid var(--border-color);
outline-offset: -1px;
background: var(--background-color-solid);
.tooltip {
opacity: 1;
transform: translateX(2px);
}
}
}
.active {
background: var(--background-color-accent);
rect {
stroke: var(--icon-default-color-active);
}
circle {
fill: var(--icon-default-color-active);
}
&:hover {
filter: saturate(0.8);
background: var(--background-color-accent);
}
} }
} }
@@ -295,7 +307,7 @@
padding: 10px; padding: 10px;
padding-left: 16px; padding-left: 16px;
width: 100%; width: 100%;
gap: 12px; gap: 8px;
height: 52px; height: 52px;
.options-container { .options-container {
@@ -318,7 +330,7 @@
.split { .split {
height: 20px; height: 20px;
width: 2px; min-width: 1px;
background: var(--text-disabled); background: var(--text-disabled);
} }
@@ -1166,8 +1178,7 @@
height: 100%; height: 100%;
width: 1px; width: 1px;
position: absolute; position: absolute;
color: var(--text-color); color: var(--accent-color);
opacity: 0.4;
font-size: var(--font-size-regular); font-size: var(--font-size-regular);
outline-offset: -1px; outline-offset: -1px;
top: 0; top: 0;
@@ -1431,6 +1442,18 @@
} }
} }
} }
.toggle-sidebar-ui-button {
svg {
transform: scaleX(-1);
}
.tooltip {
right: 56px;
&::after {
left: 100%;
bottom: 50%;
}
}
}
} }
.assets-container-main { .assets-container-main {
@@ -1598,7 +1621,11 @@
height: 100%; height: 100%;
gap: 6px; gap: 6px;
padding: 2px; padding: 2px;
.no-asset {
text-align: center;
margin: 12px;
width: 100%;
}
.assets { .assets {
width: 122px; width: 122px;
height: 95px; height: 95px;
@@ -1655,20 +1682,6 @@
} }
} }
.skeleton-wrapper {
display: flex;
.asset-name {
width: 40%;
height: 10px;
}
.asset {
width: 100%;
height: 100%;
}
}
.sidebar-left-wrapper, .sidebar-left-wrapper,
.sidebar-right-wrapper { .sidebar-right-wrapper {
transition: height 0.2s ease-in-out; transition: height 0.2s ease-in-out;

View File

@@ -1,61 +1,90 @@
.skeleton-wrapper { .skeleton-wrapper {
// max-width: 600px; margin: 0 auto;
margin: 0 auto; width: 100%;
width: 100%;
.skeleton { .skeleton {
background: var(--background-color-gray); background: var(--background-color-gray);
border-radius: 8px; border-radius: 8px;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
&::after { &::after {
content: ''; content: "";
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-image: linear-gradient(90deg, background-image: linear-gradient(
rgba(255, 255, 255, 0) 0%, 90deg,
rgba(255, 255, 255, 0.2) 20%, rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0.2) 20%,
rgba(255, 255, 255, 0) 100%); rgba(255, 255, 255, 0.39) 60%,
transform: translateX(-100%); rgba(255, 255, 255, 0) 100%
animation: shimmer 1.5s infinite; );
} transform: translateX(-100%);
animation: shimmer 1.5s infinite;
}
}
.skeleton-header {
margin-bottom: 20px;
.skeleton-title {
width: 100%;
height: 25px;
margin-bottom: 12px;
} }
.skeleton-header { .skeleton-subtitle {
margin-bottom: 20px; width: 100%;
height: 4px;
.skeleton-title {
width: 100%;
height: 25px;
margin-bottom: 12px;
}
.skeleton-subtitle {
width: 100%;
height: 4px;
}
} }
}
.skeleton-content { .skeleton-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
.skeleton-card { .skeleton-card {
width: 100%; width: 100%;
height: 15px; height: 15px;
}
} }
}
}
.asset-category-title{
width: 60%;
height: 12px;
margin-bottom: 12px;
margin-top: 4px;
}
.skeleton-content-asset{
display: flex;
height: calc(95px * 2 + 10px);
gap: 10px;
flex-wrap: wrap;
.skeleton-content {
gap: 8px;
flex-direction: column;
min-width: 122px;
min-height: 95px;
.asset-name {
width: 40%;
height: 10px;
}
.asset {
flex: 1;
width: 100%;
height: 100%;
}
}
} }
@keyframes shimmer { @keyframes shimmer {
100% { 100% {
transform: translateX(100%); transform: translateX(100%);
} }
} }

View File

@@ -326,7 +326,7 @@ export const lineConfig: LineConfig = {
}; };
export const wallConfig: WallConfig = { export const wallConfig: WallConfig = {
defaultColor: "white", // Default color of the walls defaultColor: "#f2f2f2", // Default color of the walls
height: 7, // Height of the walls height: 7, // Height of the walls
width: 0.05, // Width of the walls width: 0.05, // Width of the walls
}; };
@@ -334,7 +334,7 @@ export const wallConfig: WallConfig = {
export const floorConfig: FloorConfig = { export const floorConfig: FloorConfig = {
defaultColor: "grey", // Default color of the floors defaultColor: "grey", // Default color of the floors
height: 0.1, // Height of the floors height: 0.1, // Height of the floors
textureScale: 0.1, // Scale of the floor texture textureScale: 1, // Scale of the floor texture
}; };
export const roofConfig: RoofConfig = { export const roofConfig: RoofConfig = {
@@ -345,7 +345,7 @@ export const roofConfig: RoofConfig = {
export const aisleConfig: AisleConfig = { export const aisleConfig: AisleConfig = {
width: 0.1, // Width of the aisles width: 0.1, // Width of the aisles
height: 0.01, // Height of the aisles height: 0.01, // Height of the aisles
defaultColor: 0xffff00, // Default color of the aisles defaultColor: 0xE2AC09, // Default color of the aisles
}; };
export const zoneConfig: ZoneConfig = { export const zoneConfig: ZoneConfig = {

View File

@@ -17,7 +17,7 @@ import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
const KeyPressListener: React.FC = () => { const KeyPressListener: React.FC = () => {
const { activeModule, setActiveModule } = useModuleStore(); const { activeModule, setActiveModule } = useModuleStore();
const { setActiveSubTool } = useActiveSubTool(); const { setActiveSubTool } = useActiveSubTool();
const { toggleUI, setToggleUI } = useToggleStore(); const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
const { setToggleThreeD } = useThreeDStore(); const { setToggleThreeD } = useThreeDStore();
const { setToolMode } = useToolMode(); const { setToolMode } = useToolMode();
const { setIsPlaying } = usePlayButtonStore(); const { setIsPlaying } = usePlayButtonStore();
@@ -26,7 +26,7 @@ const KeyPressListener: React.FC = () => {
const { setAddAction } = useAddAction(); const { setAddAction } = useAddAction();
const { setSelectedWallItem } = useSelectedWallItem(); const { setSelectedWallItem } = useSelectedWallItem();
const { setActiveTool } = useActiveTool(); const { setActiveTool } = useActiveTool();
const { clearSelectedZone} = useSelectedZoneStore(); const { clearSelectedZone } = useSelectedZoneStore();
const isTextInput = (element: Element | null): boolean => const isTextInput = (element: Element | null): boolean =>
element instanceof HTMLInputElement || element instanceof HTMLInputElement ||
@@ -42,9 +42,10 @@ const KeyPressListener: React.FC = () => {
}; };
const module = modules[keyCombination]; const module = modules[keyCombination];
if (module && !toggleView) { if (module && !toggleView) {
console.log("hi");
setActiveTool("cursor"); setActiveTool("cursor");
setActiveSubTool("cursor"); setActiveSubTool("cursor");
if (module === "market") setToggleUI(false); if (module === "market") setToggleUI(false, false);
setActiveModule(module); setActiveModule(module);
} }
}; };
@@ -69,6 +70,7 @@ const KeyPressListener: React.FC = () => {
const toggleTo2D = toggleView; const toggleTo2D = toggleView;
setToggleView(!toggleTo2D); setToggleView(!toggleTo2D);
setToggleThreeD(toggleTo2D); setToggleThreeD(toggleTo2D);
setToggleUI(toggleTo2D, toggleTo2D);
if (toggleTo2D) { if (toggleTo2D) {
setSelectedWallItem(null); setSelectedWallItem(null);
setDeleteTool(false); setDeleteTool(false);
@@ -105,6 +107,29 @@ const KeyPressListener: React.FC = () => {
}; };
const handleSidebarShortcuts = (key: string) => {
if (activeModule !== "market") {
if (key === "Ctrl+\\") {
if (toggleUILeft === toggleUIRight) {
setToggleUI(!toggleUILeft, !toggleUIRight);
}
else {
setToggleUI(true, true);
}
return;
}
if (key === "Ctrl+]") {
setToggleUI(toggleUILeft, !toggleUIRight);
return;
}
if (key === "Ctrl+[") {
setToggleUI(!toggleUILeft, toggleUIRight);
return;
}
}
}
const handleKeyPress = (event: KeyboardEvent) => { const handleKeyPress = (event: KeyboardEvent) => {
if (isTextInput(document.activeElement)) return; if (isTextInput(document.activeElement)) return;
@@ -113,11 +138,8 @@ const KeyPressListener: React.FC = () => {
event.preventDefault(); event.preventDefault();
if (keyCombination === "Ctrl+\\") { // Shortcuts specific for sidebar visibility toggle and others specific to sidebar if added
if (activeModule !== "market") setToggleUI(!toggleUI); handleSidebarShortcuts(keyCombination);
return;
}
// Active module selection (builder, simulation, etc.) // Active module selection (builder, simulation, etc.)
handleModuleSwitch(keyCombination); handleModuleSwitch(keyCombination);
// Common editing tools: cursor | delete | free-hand // Common editing tools: cursor | delete | free-hand
@@ -132,6 +154,7 @@ const KeyPressListener: React.FC = () => {
if (keyCombination === "ESCAPE") { if (keyCombination === "ESCAPE") {
setActiveTool("cursor"); setActiveTool("cursor");
setActiveSubTool("cursor");
setIsPlaying(false); setIsPlaying(false);
clearSelectedZone(); clearSelectedZone();
} }
@@ -146,7 +169,7 @@ const KeyPressListener: React.FC = () => {
window.addEventListener("keydown", handleKeyPress); window.addEventListener("keydown", handleKeyPress);
return () => window.removeEventListener("keydown", handleKeyPress); return () => window.removeEventListener("keydown", handleKeyPress);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeModule, toggleUI, toggleView]); }, [activeModule, toggleUIRight, toggleUILeft, toggleView]);
return null; return null;
}; };

View File

@@ -4,7 +4,7 @@ export { };
function setTheme() { function setTheme() {
const savedTheme: string | null = localStorage.getItem('theme'); const savedTheme: string | null = localStorage.getItem('theme');
const systemPrefersDark: boolean = window.matchMedia('(prefers-color-scheme: dark)').matches; const systemPrefersDark: boolean = window.matchMedia('(prefers-color-scheme: dark)').matches;
const defaultTheme: string = savedTheme || (systemPrefersDark ? 'dark' : 'light'); const defaultTheme: string = savedTheme ?? (systemPrefersDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', defaultTheme); document.documentElement.setAttribute('data-theme', defaultTheme);
localStorage.setItem('theme', defaultTheme); localStorage.setItem('theme', defaultTheme);
} }