Refactor styles for improved theme management, enhance input components, and add scene styles

This commit is contained in:
Vishnu 2025-03-31 18:06:44 +05:30
parent 8fc4453cee
commit b125989ae7
18 changed files with 556 additions and 371 deletions

View File

@ -1,9 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en" data-theme="light">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> <meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no"
/>
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
@ -26,7 +29,7 @@
--> -->
<title>Dwinzo (beta)</title> <title>Dwinzo (beta)</title>
</head> </head>
<body data-theme="light"> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<div id="root-over"></div> <div id="root-over"></div>

View File

@ -31,9 +31,9 @@ const Header: React.FC = () => {
> >
Share Share
</div> </div>
<div className="app-docker-button"> {/* <div className="app-docker-button">
<AppDockIcon /> <AppDockIcon />
</div> </div> */}
</div> </div>
<div className="split"></div> <div className="split"></div>
<div className="users-container"> <div className="users-container">
@ -52,12 +52,7 @@ const Header: React.FC = () => {
))} ))}
</div> </div>
<div className="user-profile-container"> <div className="user-profile-container">
<div <div className="user-profile">{userName[0]}</div>
className="user-profile"
style={{ background: "var(--accent-color)" }}
>
{userName[0]}
</div>
<div className="user-organization"> <div className="user-organization">
<img src={orgImg} alt="" /> <img src={orgImg} alt="" />
</div> </div>

View File

@ -9,9 +9,13 @@ import RenameInput from "../../../ui/inputs/RenameInput";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown"; import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import { handleResize } from "../../../../functions/handleResizePannel"; import { handleResize } from "../../../../functions/handleResizePannel";
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store"; import {
import * as THREE from 'three'; useSelectedActionSphere,
import * as Types from '../../../../types/world/worldTypes'; useSelectedPath,
useSimulationPaths,
} from "../../../../store/store";
import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes";
import InputToggle from "../../../ui/inputs/InputToggle"; import InputToggle from "../../../ui/inputs/InputToggle";
const ConveyorMechanics: React.FC = () => { const ConveyorMechanics: React.FC = () => {
@ -25,7 +29,9 @@ const ConveyorMechanics: React.FC = () => {
const selectedPoint = useMemo(() => { const selectedPoint = useMemo(() => {
if (!selectedActionSphere) return null; if (!selectedActionSphere) return null;
return simulationPaths return simulationPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor") .filter(
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
)
.flatMap((path) => path.points) .flatMap((path) => path.points)
.find((point) => point.uuid === selectedActionSphere.point.uuid); .find((point) => point.uuid === selectedActionSphere.point.uuid);
}, [selectedActionSphere, simulationPaths]); }, [selectedActionSphere, simulationPaths]);
@ -43,11 +49,11 @@ const ConveyorMechanics: React.FC = () => {
const newAction = { const newAction = {
uuid: THREE.MathUtils.generateUUID(), uuid: THREE.MathUtils.generateUUID(),
name: `Action ${actionIndex + 1}`, name: `Action ${actionIndex + 1}`,
type: 'Inherit', type: "Inherit",
material: 'Inherit', material: "Inherit",
delay: 'Inherit', delay: "Inherit",
spawnInterval: 'Inherit', spawnInterval: "Inherit",
isUsed: false isUsed: false,
}; };
return { ...point, actions: [...point.actions, newAction] }; return { ...point, actions: [...point.actions, newAction] };
@ -71,7 +77,12 @@ const ConveyorMechanics: React.FC = () => {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.point.uuid
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) } ? {
...point,
actions: point.actions.filter(
(action) => action.uuid !== uuid
),
}
: point : point
), ),
} }
@ -97,9 +108,16 @@ const ConveyorMechanics: React.FC = () => {
? { ? {
...action, ...action,
type: actionType, type: actionType,
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material, material:
delay: actionType === 'Delay' ? 'Inherit' : action.delay, actionType === "Spawn" || actionType === "Swap"
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval ? "Inherit"
: action.material,
delay:
actionType === "Delay" ? "Inherit" : action.delay,
spawnInterval:
actionType === "Spawn"
? "Inherit"
: action.spawnInterval,
} }
: action : action
), ),
@ -115,15 +133,17 @@ const ConveyorMechanics: React.FC = () => {
// Update the selected item to reflect changes // Update the selected item to reflect changes
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
const updatedAction = updatedPaths const updatedAction = updatedPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor") .filter(
.flatMap(path => path.points) (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
.find(p => p.uuid === selectedActionSphere.point.uuid) )
?.actions.find(a => a.uuid === uuid); .flatMap((path) => path.points)
.find((p) => p.uuid === selectedActionSphere.point.uuid)
?.actions.find((a) => a.uuid === uuid);
if (updatedAction) { if (updatedAction) {
setSelectedItem({ setSelectedItem({
type: "action", type: "action",
item: updatedAction item: updatedAction,
}); });
} }
} }
@ -143,7 +163,7 @@ const ConveyorMechanics: React.FC = () => {
...point, ...point,
actions: point.actions.map((action) => actions: point.actions.map((action) =>
action.uuid === uuid && action.uuid === uuid &&
(action.type === 'Spawn' || action.type === 'Swap') (action.type === "Spawn" || action.type === "Swap")
? { ...action, material } ? { ...action, material }
: action : action
), ),
@ -162,8 +182,8 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem, ...selectedItem,
item: { item: {
...selectedItem.item, ...selectedItem.item,
material material,
} },
}); });
} }
}; };
@ -192,7 +212,10 @@ const ConveyorMechanics: React.FC = () => {
setSimulationPaths(updatedPaths); setSimulationPaths(updatedPaths);
}; };
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => { const handleSpawnIntervalChange = (
uuid: string,
spawnInterval: number | string
) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationPaths.map((path) =>
@ -204,7 +227,9 @@ const ConveyorMechanics: React.FC = () => {
? { ? {
...point, ...point,
actions: point.actions.map((action) => actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, spawnInterval } : action action.uuid === uuid
? { ...action, spawnInterval }
: action
), ),
} }
: point : point
@ -240,9 +265,9 @@ const ConveyorMechanics: React.FC = () => {
const newTrigger = { const newTrigger = {
uuid: THREE.MathUtils.generateUUID(), uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`, name: `Trigger ${triggerIndex + 1}`,
type: '', type: "",
bufferTime: 0, bufferTime: 0,
isUsed: false isUsed: false,
}; };
return { ...point, triggers: [...point.triggers, newTrigger] }; return { ...point, triggers: [...point.triggers, newTrigger] };
@ -265,7 +290,12 @@ const ConveyorMechanics: React.FC = () => {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.point.uuid
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) } ? {
...point,
triggers: point.triggers.filter(
(trigger) => trigger.uuid !== uuid
),
}
: point : point
), ),
} }
@ -287,7 +317,9 @@ const ConveyorMechanics: React.FC = () => {
? { ? {
...point, ...point,
triggers: point.triggers.map((trigger) => triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger trigger.uuid === uuid
? { ...trigger, type: triggerType }
: trigger
), ),
} }
: point : point
@ -309,7 +341,6 @@ const ConveyorMechanics: React.FC = () => {
} }
}; };
// Update the toggle handlers to immediately update the selected item // Update the toggle handlers to immediately update the selected item
const handleActionToggle = (uuid: string) => { const handleActionToggle = (uuid: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
@ -340,8 +371,8 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem, ...selectedItem,
item: { item: {
...selectedItem.item, ...selectedItem.item,
isUsed: !selectedItem.item.isUsed isUsed: !selectedItem.item.isUsed,
} },
}); });
} }
}; };
@ -377,8 +408,8 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem, ...selectedItem,
item: { item: {
...selectedItem.item, ...selectedItem.item,
isUsed: !selectedItem.item.isUsed isUsed: !selectedItem.item.isUsed,
} },
}); });
} }
}; };
@ -395,7 +426,9 @@ const ConveyorMechanics: React.FC = () => {
? { ? {
...point, ...point,
triggers: point.triggers.map((trigger) => triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, bufferTime } : trigger trigger.uuid === uuid
? { ...trigger, bufferTime }
: trigger
), ),
} }
: point : point
@ -412,13 +445,16 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem, ...selectedItem,
item: { item: {
...selectedItem.item, ...selectedItem.item,
bufferTime bufferTime,
} },
}); });
} }
}; };
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null); const [selectedItem, setSelectedItem] = useState<{
type: "action" | "trigger";
item: any;
} | null>(null);
useEffect(() => { useEffect(() => {
setSelectedItem(null); setSelectedItem(null);
@ -426,21 +462,20 @@ const ConveyorMechanics: React.FC = () => {
return ( return (
<div className="machine-mechanics-container"> <div className="machine-mechanics-container">
{!selectedPath && {!selectedPath && (
<div className="machine-mechanics-header"> <div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"} {selectedActionSphere?.path?.modelName || "point name not found"}
</div> </div>
} )}
{selectedPath &&
{selectedPath && (
<div className="machine-mechanics-header"> <div className="machine-mechanics-header">
{selectedPath.path.modelName || "path name not found"} {selectedPath.path.modelName || "path name not found"}
</div> </div>
} )}
<div className="machine-mechanics-content-container"> <div className="machine-mechanics-content-container">
{!selectedPath && {!selectedPath && (
<> <>
<div className="actions"> <div className="actions">
<div className="header"> <div className="header">
@ -458,7 +493,8 @@ const ConveyorMechanics: React.FC = () => {
{selectedPoint?.actions.map((action) => ( {selectedPoint?.actions.map((action) => (
<div <div
key={action.uuid} key={action.uuid}
className={`list-item ${selectedItem?.type === "action" && className={`list-item ${
selectedItem?.type === "action" &&
selectedItem.item?.uuid === action.uuid selectedItem.item?.uuid === action.uuid
? "active" ? "active"
: "" : ""
@ -466,8 +502,11 @@ const ConveyorMechanics: React.FC = () => {
> >
<div <div
className="value" className="value"
onClick={() => setSelectedItem({ type: "action", item: action })} onClick={() =>
setSelectedItem({ type: "action", item: action })
}
> >
<input type="radio" name="action" id="action" defaultChecked={action.isUsed}/>
<RenameInput value={action.name} /> <RenameInput value={action.name} />
</div> </div>
<div <div
@ -504,7 +543,8 @@ const ConveyorMechanics: React.FC = () => {
{selectedPoint?.triggers.map((trigger) => ( {selectedPoint?.triggers.map((trigger) => (
<div <div
key={trigger.uuid} key={trigger.uuid}
className={`list-item ${selectedItem?.type === "trigger" && className={`list-item ${
selectedItem?.type === "trigger" &&
selectedItem.item?.uuid === trigger.uuid selectedItem.item?.uuid === trigger.uuid
? "active" ? "active"
: "" : ""
@ -512,8 +552,11 @@ const ConveyorMechanics: React.FC = () => {
> >
<div <div
className="value" className="value"
onClick={() => setSelectedItem({ type: "trigger", item: trigger })} onClick={() =>
setSelectedItem({ type: "trigger", item: trigger })
}
> >
<input type="radio" name="trigger" id="trigger" defaultChecked={trigger.isUsed} />
<RenameInput value={trigger.name} /> <RenameInput value={trigger.name} />
</div> </div>
<div <div
@ -535,7 +578,7 @@ const ConveyorMechanics: React.FC = () => {
</div> </div>
</div> </div>
</> </>
} )}
<div className="selected-properties-container"> <div className="selected-properties-container">
{selectedItem && ( {selectedItem && (
@ -553,48 +596,69 @@ const ConveyorMechanics: React.FC = () => {
<LabledDropdown <LabledDropdown
defaultOption={selectedItem.item.type} defaultOption={selectedItem.item.type}
options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]} options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]}
onSelect={(option) => handleActionSelect(selectedItem.item.uuid, option)} onSelect={(option) =>
handleActionSelect(selectedItem.item.uuid, option)
}
/> />
{/* Only show material dropdown for Spawn/Swap actions */} {/* Only show material dropdown for Spawn/Swap actions */}
{(selectedItem.item.type === 'Spawn' || selectedItem.item.type === 'Swap') && ( {(selectedItem.item.type === "Spawn" ||
selectedItem.item.type === "Swap") && (
<LabledDropdown <LabledDropdown
label={selectedItem.item.type === 'Spawn' ? 'Spawn Material' : 'Swap Material'} label={
selectedItem.item.type === "Spawn"
? "Spawn Material"
: "Swap Material"
}
defaultOption={selectedItem.item.material} defaultOption={selectedItem.item.material}
options={["Inherit", "Crate", "Box"]} options={["Inherit", "Crate", "Box"]}
onSelect={(option) => handleMaterialSelect(selectedItem.item.uuid, option)} onSelect={(option) =>
handleMaterialSelect(selectedItem.item.uuid, option)
}
/> />
)} )}
{/* Only show delay input for Delay actions */} {/* Only show delay input for Delay actions */}
{selectedItem.item.type === 'Delay' && ( {selectedItem.item.type === "Delay" && (
<InputWithDropDown <InputWithDropDown
label="Delay Time" label="Delay Time"
value={selectedItem.item.delay === 'Inherit' value={
selectedItem.item.delay === "Inherit"
? undefined ? undefined
: selectedItem.item.delay} : selectedItem.item.delay
}
onChange={(value) => { onChange={(value) => {
const numValue = parseInt(value); const numValue = parseInt(value);
handleDelayChange( handleDelayChange(
selectedItem.item.uuid, selectedItem.item.uuid,
!value ? 'Inherit' : numValue !value ? "Inherit" : numValue
); );
}} }}
/> />
)} )}
{/* Only show spawn interval for Spawn actions */} {/* Only show spawn interval for Spawn actions */}
{selectedItem.item.type === 'Spawn' && ( {selectedItem.item.type === "Spawn" && (
<InputWithDropDown <InputWithDropDown
label="Spawn Interval" label="Spawn Interval"
min={0} min={0}
defaultValue={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()} defaultValue={
value={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()} selectedItem.item.spawnInterval === "Inherit"
? ""
: selectedItem.item.spawnInterval.toString()
}
value={
selectedItem.item.spawnInterval === "Inherit"
? ""
: selectedItem.item.spawnInterval.toString()
}
onChange={(value) => { onChange={(value) => {
handleSpawnIntervalChange(selectedItem.item.uuid, (value === "") ? "Inherit" : parseInt(value)); handleSpawnIntervalChange(
selectedItem.item.uuid,
value === "" ? "Inherit" : parseInt(value)
);
}} }}
/> />
)} )}
</> </>
)} )}
@ -609,9 +673,13 @@ const ConveyorMechanics: React.FC = () => {
/> />
<LabledDropdown <LabledDropdown
defaultOption={selectedItem.item.type || "Select Trigger Type"} defaultOption={
selectedItem.item.type || "Select Trigger Type"
}
options={["On-Hit", "Buffer"]} options={["On-Hit", "Buffer"]}
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)} onSelect={(option) =>
handleTriggerSelect(selectedItem.item.uuid, option)
}
/> />
{selectedItem.item.type === "Buffer" && ( {selectedItem.item.type === "Buffer" && (
@ -619,23 +687,34 @@ const ConveyorMechanics: React.FC = () => {
label="Buffer Time" label="Buffer Time"
value={selectedItem.item.bufferTime.toString()} value={selectedItem.item.bufferTime.toString()}
onChange={(value) => { onChange={(value) => {
handleTriggerBufferTimeChange(selectedItem.item.uuid, parseInt(value)); handleTriggerBufferTimeChange(
selectedItem.item.uuid,
parseInt(value)
);
}} }}
/> />
)} )}
</> </>
)} )}
</> </>
)} )}
{selectedPath && !selectedItem && ( {selectedPath && !selectedItem && (
<div key={selectedPath?.path.modeluuid || "none"} className="speed-control"> <div
key={selectedPath?.path.modeluuid || "none"}
className="speed-control"
>
<InputWithDropDown <InputWithDropDown
label="Conveyor Speed" label="Conveyor Speed"
min={0} min={0}
value={selectedPath.path.speed === "Inherit" ? "" : selectedPath.path.speed.toString()} value={
onChange={(value) => handleSpeedChange((value === "") ? "Inherit" : parseInt(value))} selectedPath.path.speed === "Inherit"
? ""
: selectedPath.path.speed.toString()
}
onChange={(value) =>
handleSpeedChange(value === "" ? "Inherit" : parseInt(value))
}
/> />
</div> </div>
)} )}

View File

@ -1,5 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { ArrowIcon } from "../../icons/ExportCommonIcons"; import { ArrowIcon } from "../../icons/ExportCommonIcons";
import { toggleTheme } from "../../../utils/theme";
interface MenuBarProps { interface MenuBarProps {
setOpenMenu: (isOpen: boolean) => void; // Function to update menu state setOpenMenu: (isOpen: boolean) => void; // Function to update menu state
@ -22,6 +23,13 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
})); }));
}; };
function handleThemeChange(){
toggleTheme();
window.location.reload();
}
const savedTheme: string | null = localStorage.getItem("theme") || "light";
return ( return (
<div <div
className="menu-bar" className="menu-bar"
@ -381,6 +389,22 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
<div className="menu-button">Export as...</div> <div className="menu-button">Export as...</div>
</div> </div>
<div
className="menu-button-container"
onMouseEnter={() => setActiveMenu("theme")}
onMouseLeave={() => {
setActiveMenu(null);
setActiveSubMenu(null);
}}
onClick={() => {
handleThemeChange();
}}
>
<div className="menu-button">
Theme <div className="value">{savedTheme}</div>
</div>
</div>
{/* Apps Menu */} {/* Apps Menu */}
{/* <div {/* <div
className="menu-button-container" className="menu-button-container"

View File

@ -1,32 +1,55 @@
import { useEffect, useState } from "react" import { useEffect, useState } from "react";
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi"; import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
import * as THREE from "three"; import * as THREE from "three";
import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store"; import {
useActiveLayer,
useDeletedLines,
useNewLines,
useToggleView,
} from "../../../../store/store";
import objectLinesToArray from "./lineConvertions/objectLinesToArray"; import objectLinesToArray from "./lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei"; import { Html } from "@react-three/drei";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
const DistanceText = () => { const DistanceText = () => {
const [lines, setLines] = useState<{ distance: string; position: THREE.Vector3; userData: Types.Line; layer: string }[]>([]); const [lines, setLines] = useState<
{
distance: string;
position: THREE.Vector3;
userData: Types.Line;
layer: string;
}[]
>([]);
const { activeLayer } = useActiveLayer(); const { activeLayer } = useActiveLayer();
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { newLines, setNewLines } = useNewLines(); const { newLines, setNewLines } = useNewLines();
const { deletedLines, setDeletedLines } = useDeletedLines(); const { deletedLines, setDeletedLines } = useDeletedLines();
useEffect(() => { useEffect(() => {
const email = localStorage.getItem('email') const email = localStorage.getItem("email");
if (!email) return; if (!email) return;
const organization = (email.split("@")[1]).split(".")[0]; const organization = email.split("@")[1].split(".")[0];
getLines(organization).then((data) => { getLines(organization).then((data) => {
data = objectLinesToArray(data); data = objectLinesToArray(data);
const lines = data.filter((line: Types.Line) => line[0][2] === activeLayer) const lines = data
.filter((line: Types.Line) => line[0][2] === activeLayer)
.map((line: Types.Line) => { .map((line: Types.Line) => {
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z); const point1 = new THREE.Vector3(
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z); line[0][0].x,
line[0][0].y,
line[0][0].z
);
const point2 = new THREE.Vector3(
line[1][0].x,
line[1][0].y,
line[1][0].z
);
const distance = point1.distanceTo(point2); const distance = point1.distanceTo(point2);
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2); const midpoint = new THREE.Vector3()
.addVectors(point1, point2)
.divideScalar(2);
return { return {
distance: distance.toFixed(1), distance: distance.toFixed(1),
position: midpoint, position: midpoint,
@ -34,18 +57,28 @@ const DistanceText = () => {
layer: activeLayer, layer: activeLayer,
}; };
}); });
setLines(lines) setLines(lines);
}) });
}, [activeLayer]) }, [activeLayer]);
useEffect(() => { useEffect(() => {
if (newLines.length > 0) { if (newLines.length > 0) {
if (newLines[0][0][2] !== activeLayer) return; if (newLines[0][0][2] !== activeLayer) return;
const newLinesData = newLines.map((line: Types.Line) => { const newLinesData = newLines.map((line: Types.Line) => {
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z); const point1 = new THREE.Vector3(
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z); line[0][0].x,
line[0][0].y,
line[0][0].z
);
const point2 = new THREE.Vector3(
line[1][0].x,
line[1][0].y,
line[1][0].z
);
const distance = point1.distanceTo(point2); const distance = point1.distanceTo(point2);
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2); const midpoint = new THREE.Vector3()
.addVectors(point1, point2)
.divideScalar(2);
return { return {
distance: distance.toFixed(1), distance: distance.toFixed(1),
@ -59,12 +92,16 @@ const DistanceText = () => {
} }
}, [newLines, activeLayer]); }, [newLines, activeLayer]);
useEffect(() => { useEffect(() => {
if ((deletedLines as Types.Lines).length > 0) { if ((deletedLines as Types.Lines).length > 0) {
setLines((prevLines) => setLines((prevLines) =>
prevLines.filter( prevLines.filter(
(line) => !deletedLines.some((deletedLine: any) => deletedLine[0][1] === line.userData[0][1] && deletedLine[1][1] === line.userData[1][1]) (line) =>
!deletedLines.some(
(deletedLine: any) =>
deletedLine[0][1] === line.userData[0][1] &&
deletedLine[1][1] === line.userData[1][1]
)
) )
); );
setDeletedLines([]); setDeletedLines([]);
@ -74,17 +111,33 @@ const DistanceText = () => {
return ( return (
<> <>
{toggleView && ( {toggleView && (
<group name='Distance_Text'> <group name="Distance_Text">
{lines.map((text) => ( {lines.map((text) => (
<Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} > <Html
<div key={`${text.userData[0][1]}_${text.userData[1][1]}`} className={`Distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`} >{text.distance} m</div> // data
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
userData={text.userData}
position={[text.position.x, 1, text.position.z]}
// class
wrapperClass="distance-text-wrapper"
className="distance-text"
// other
zIndexRange={[100, 0]}
prepend
sprite
>
<div
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
className={`distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`}
>
{text.distance} m
</div>
</Html> </Html>
))} ))}
</group> </group>
)} )}
</> </>
) );
};
}
export default DistanceText; export default DistanceText;

View File

@ -434,9 +434,9 @@ const ZoneGroup: React.FC = () => {
const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]); const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]);
const planeWidth = point1.distanceTo(point2); const planeWidth = point1.distanceTo(point2);
const planeHeight = CONSTANTS.wallConfig.height; const planeHeight = CONSTANTS.zoneConfig.height;
const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.wallConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.wallConfig.height), (point1.z + point2.z) / 2); const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.zoneConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.zoneConfig.height), (point1.z + point2.z) / 2);
const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x); const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x);

View File

@ -1,9 +1,9 @@
import * as THREE from 'three';
import { useToggleView } from '../../../store/store'; import { useToggleView } from '../../../store/store';
import * as CONSTANTS from '../../../types/world/worldConstants'; import * as CONSTANTS from '../../../types/world/worldConstants';
const Ground = ({ grid, plane }: any) => { const Ground = ({ grid, plane }: any) => {
const { toggleView, setToggleView } = useToggleView(); const { toggleView } = useToggleView();
const savedTheme: string | null = localStorage.getItem('theme');
return ( return (

View File

@ -1,11 +1,11 @@
import { useMemo, useState } from "react"; import { useMemo } from "react";
import { Canvas } from "@react-three/fiber"; import { Canvas } from "@react-three/fiber";
import { Environment, KeyboardControls } from "@react-three/drei"; import { Environment, KeyboardControls } from "@react-three/drei";
import World from "./world/world"; import World from "./world/world";
import Controls from "./controls/controls"; import Controls from "./controls/controls";
import TransformControl from "./controls/transformControls"; import TransformControl from "./controls/transformControls";
import PostProcessing from "./postProcessing/postProcessing" import PostProcessing from "./postProcessing/postProcessing";
import Sun from "./environment/sky"; import Sun from "./environment/sky";
import CamModelsGroup from "../collaboration/collabCams"; import CamModelsGroup from "../collaboration/collabCams";
import Shadows from "./environment/shadow"; import Shadows from "./environment/shadow";
@ -15,33 +15,31 @@ import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr";
import SelectionControls from "./controls/selection/selectionControls"; import SelectionControls from "./controls/selection/selectionControls";
import MeasurementTool from "./tools/measurementTool"; import MeasurementTool from "./tools/measurementTool";
import Simulation from "../simulation/simulation"; import Simulation from "../simulation/simulation";
import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets";
// import Simulation from "./simulationtemp/simulation"; // import Simulation from "./simulationtemp/simulation";
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget"; import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
import ProductionCapacity from "../../components/layout/3D-cards/cards/ProductionCapacity";
import Dropped3dWidgets from "../../components/ui/componets/Dropped3dWidget"; import Dropped3dWidgets from "../../components/ui/componets/Dropped3dWidget";
import { useWidgetSubOption } from "../../store/store";
export default function Scene() { export default function Scene() {
const map = useMemo(
const map = useMemo(() => [ () => [
{ name: "forward", keys: ["ArrowUp", "w", "W"] }, { name: "forward", keys: ["ArrowUp", "w", "W"] },
{ name: "backward", keys: ["ArrowDown", "s", "S"] }, { name: "backward", keys: ["ArrowDown", "s", "S"] },
{ name: "left", keys: ["ArrowLeft", "a", "A"] }, { name: "left", keys: ["ArrowLeft", "a", "A"] },
{ name: "right", keys: ["ArrowRight", "d", "D"] }, { name: "right", keys: ["ArrowRight", "d", "D"] },
], []) ],
[]
);
const savedTheme: string | null = localStorage.getItem("theme");
return ( return (
<KeyboardControls map={map}> <KeyboardControls map={map}>
<Canvas <Canvas
// style={{ width: "100vw", height: "100vh" }}
eventPrefix="client" eventPrefix="client"
gl={{ powerPreference: "high-performance", antialias: true }} gl={{ powerPreference: "high-performance", antialias: true }}
onContextMenu={(e) => { onContextMenu={(e) => {
e.preventDefault(); e.preventDefault();
}} }}
> >
<Dropped3dWidgets /> <Dropped3dWidgets />
<Controls /> <Controls />
@ -52,7 +50,7 @@ export default function Scene() {
<ZoneCentreTarget /> <ZoneCentreTarget />
<Simulation /> <Simulation />
<PostProcessing /> <PostProcessing />
<Sun /> {savedTheme !== "dark" && <Sun />}
<Shadows /> <Shadows />
<CamModelsGroup /> <CamModelsGroup />
<MqttEvents /> <MqttEvents />

View File

@ -27,7 +27,7 @@ $input-text-color-dark: #b5b5c8; // Input field text color for dark mode
// Accent colors // Accent colors
$accent-color: #6f42c1; // Primary accent color $accent-color: #6f42c1; // Primary accent color
$accent-color-dark: #b392f0; // Primary accent color for dark mode $accent-color-dark: #c4abf1; // Primary accent color for dark mode
$highlight-accent-color: #e0dfff; // Highlighted accent for light mode $highlight-accent-color: #e0dfff; // Highlighted accent for light mode
$highlight-accent-color-dark: #403e6a; // Highlighted accent for dark mode $highlight-accent-color-dark: #403e6a; // Highlighted accent for dark mode
@ -45,6 +45,7 @@ $border-color-dark: #403e6a; // Border color for dark mode
// Shadow color // Shadow color
$shadow-color: #3c3c431a; // Shadow base color for light and dark mode $shadow-color: #3c3c431a; // Shadow base color for light and dark mode
$shadow-color-dark: #8f8f8f1a; // Shadow base color for light and dark mode
// Gradients // Gradients
$acent-gradient-dark: linear-gradient( $acent-gradient-dark: linear-gradient(

View File

@ -58,7 +58,7 @@
--border-color: #{$border-color-dark}; // Border color for dark theme --border-color: #{$border-color-dark}; // Border color for dark theme
// Shadow variables // Shadow variables
--shadow-main-dark: #{$shadow-color}; // Main shadow color --shadow-main-dark: #{$shadow-color-dark}; // Main shadow color
--box-shadow-light: 0px 2px 4px var(--shadow-main-dark); // Light shadow --box-shadow-light: 0px 2px 4px var(--shadow-main-dark); // Light shadow
--box-shadow-medium: 0px 4px 8px var(--shadow-main-dark); // Medium shadow --box-shadow-medium: 0px 4px 8px var(--shadow-main-dark); // Medium shadow
--box-shadow-heavy: 0px 8px 16px var(--shadow-main-dark); // Heavy shadow --box-shadow-heavy: 0px 8px 16px var(--shadow-main-dark); // Heavy shadow

View File

@ -1,6 +1,22 @@
@use "../abstracts/variables" as *; @use "../abstracts/variables" as *;
@use "../abstracts/mixins" as *; @use "../abstracts/mixins" as *;
// global input style
input {
width: 100%;
padding: 2px 4px;
border-radius: #{$border-radius-small};
border: 1px solid var(--border-color);
outline: none;
background: transparent;
&:focus,
&:active {
border: 1px solid var(--accent-color);
}
}
.input-value { .input-value {
color: var(--input-text-color); color: var(--input-text-color);
font-size: var(--font-size-regular); font-size: var(--font-size-regular);
@ -169,7 +185,6 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
cursor: pointer; cursor: pointer;
border: 1px solid var(--primary-color);
border-radius: 6px; border-radius: 6px;
background-color: var(--background-color); background-color: var(--background-color);
} }
@ -214,8 +229,8 @@
position: relative; position: relative;
.dropdown { .dropdown {
top: 3px; top: 2px;
right: 3px; right: 2px;
position: absolute; position: absolute;
background: var(--highlight-accent-color); background: var(--highlight-accent-color);
border-radius: #{$border-radius-small}; border-radius: #{$border-radius-small};
@ -228,19 +243,6 @@
} }
} }
input {
width: 100%;
padding: 2px 4px;
border-radius: #{$border-radius-small};
border: 1px solid var(--border-color);
outline: none;
&:focus,
&:active {
border: 1px solid var(--accent-color);
}
}
.eye-dropper-input-container { .eye-dropper-input-container {
display: flex; display: flex;
align-items: center; align-items: center;
@ -607,6 +609,7 @@ input {
input { input {
border: none; border: none;
background: transparent;
&::placeholder { &::placeholder {
color: var(--text-disabled); color: var(--text-disabled);

View File

@ -96,7 +96,10 @@
} }
&:hover { &:hover {
background-color: var(--highlight-accent-color); background-color: var(--highlight-accent-color);
color: var(--highlight-accent-color); span,
.menu-item-right span {
color: var(--accent-color);
}
} }
.menu-item-right { .menu-item-right {
@ -138,7 +141,9 @@
color: var(--text-color); color: var(--text-color);
&:hover { &:hover {
background-color: var(--highlight-accent-color); background-color: var(--highlight-accent-color);
color: var(--highlight-accent-color); span {
color: var(--accent-color);
}
} }
.shortcut { .shortcut {
color: var(--text-color); color: var(--text-color);
@ -150,7 +155,9 @@
&:hover { &:hover {
background-color: var(--highlight-accent-color); background-color: var(--highlight-accent-color);
color: var(--highlight-accent-color); .menu-button {
color: var(--accent-color);
}
} }
} }
} }

View File

@ -253,6 +253,10 @@
.user-profile-container { .user-profile-container {
display: flex; display: flex;
.user-profile{
background: var(--accent-color);
color: var(--primary-color);
}
.user-organization { .user-organization {
height: 26px; height: 26px;
@ -665,6 +669,10 @@
font-weight: var(--font-weight-regular); font-weight: var(--font-weight-regular);
padding: 8px 0; padding: 8px 0;
} }
.input-toggle-container{
padding: 0;
margin-bottom: 6px;
}
.value-field-container { .value-field-container {
margin-bottom: 6px; margin-bottom: 6px;

View File

@ -32,7 +32,10 @@
@use 'layout/toast'; @use 'layout/toast';
// pages // pages
@use 'pages/dashboard.scss'; @use 'pages/dashboard';
@use 'pages/home'; @use 'pages/home';
@use 'pages/realTimeViz'; @use 'pages/realTimeViz';
@use 'pages/userAuth'; @use 'pages/userAuth';
//
@use './scene/scene'

View File

@ -22,7 +22,7 @@
min-height: 83px; min-height: 83px;
background: var(--background-color); background: var(--background-color);
border: 1.23px solid var(--border-color); border: 1.23px solid var(--border-color);
box-shadow: 0px 4.91px 4.91px 0px #0000001c; box-shadow: var(--box-shadow-heavy);
border-radius: $border-radius-medium; border-radius: $border-radius-medium;
padding: 18px; padding: 18px;
position: absolute; position: absolute;
@ -31,6 +31,7 @@
.scene-container { .scene-container {
overflow: hidden; overflow: hidden;
background: #232323;
} }
.icon { .icon {

View File

@ -0,0 +1,23 @@
@use "../abstracts/variables" as *;
@use "../abstracts/mixins" as *;
.distance-text-wrapper {
pointer-events: none !important;
}
.distance-text {
pointer-events: none !important;
.distance {
position: absolute;
transform: translate(-50%, -50%) scale(.8);
pointer-events: none !important;
white-space: nowrap;
// style
font-size: var(--font-size-large);
padding: 2px 8px;
background: var(--primary-color);
color: var(--accent-color);
outline: 1px solid var(--accent-color);
border-radius: #{$border-radius-medium};
box-shadow: var(--box-shadow-light);
}
}

View File

@ -1,3 +1,5 @@
const savedTheme: string | null = localStorage.getItem("theme");
export type Controls = { export type Controls = {
azimuthRotateSpeed: number; azimuthRotateSpeed: number;
polarRotateSpeed: number; polarRotateSpeed: number;
@ -62,7 +64,6 @@ export type GridConfig = {
divisions: number; divisions: number;
primaryColor: string; primaryColor: string;
secondaryColor: string; secondaryColor: string;
position2D: [x: number, y: number, z: number]; position2D: [x: number, y: number, z: number];
position3D: [x: number, y: number, z: number]; position3D: [x: number, y: number, z: number];
} }
@ -71,7 +72,6 @@ export type PlaneConfig = {
position2D: [x: number, y: number, z: number]; position2D: [x: number, y: number, z: number];
position3D: [x: number, y: number, z: number]; position3D: [x: number, y: number, z: number];
rotation: number; rotation: number;
width: number; width: number;
height: number; height: number;
color: string; color: string;
@ -79,7 +79,6 @@ export type PlaneConfig = {
export type ShadowConfig = { export type ShadowConfig = {
shadowOffset: number, shadowOffset: number,
shadowmapSizewidth: number, shadowmapSizewidth: number,
shadowmapSizeheight: number, shadowmapSizeheight: number,
shadowcamerafar: number, shadowcamerafar: number,
@ -90,10 +89,8 @@ export type ShadowConfig = {
shadowcameraright: number, shadowcameraright: number,
shadowbias: number, shadowbias: number,
shadownormalBias: number, shadownormalBias: number,
shadowMaterialPosition: [x: number, y: number, z: number], shadowMaterialPosition: [x: number, y: number, z: number],
shadowMaterialRotation: [x: number, y: number, z: number], shadowMaterialRotation: [x: number, y: number, z: number],
shadowMaterialOpacity: number, shadowMaterialOpacity: number,
} }
@ -117,12 +114,10 @@ export type PointConfig = {
defaultOuterColor: string; defaultOuterColor: string;
deleteColor: string; deleteColor: string;
boxScale: [number, number, number]; boxScale: [number, number, number];
wallOuterColor: string; wallOuterColor: string;
floorOuterColor: string; floorOuterColor: string;
aisleOuterColor: string; aisleOuterColor: string;
zoneOuterColor: string; zoneOuterColor: string;
snappingThreshold: number; snappingThreshold: number;
} }
@ -130,17 +125,13 @@ export type LineConfig = {
tubularSegments: number; tubularSegments: number;
radius: number; radius: number;
radialSegments: number; radialSegments: number;
wallName: string; wallName: string;
floorName: string; floorName: string;
aisleName: string; aisleName: string;
zoneName: string; zoneName: string;
referenceName: string; referenceName: string;
lineIntersectionPoints: number; lineIntersectionPoints: number;
defaultColor: string; defaultColor: string;
wallColor: string; wallColor: string;
floorColor: string; floorColor: string;
aisleColor: string; aisleColor: string;
@ -157,7 +148,6 @@ export type WallConfig = {
export type FloorConfig = { export type FloorConfig = {
defaultColor: string; defaultColor: string;
height: number; height: number;
textureScale: number; textureScale: number;
} }
@ -169,13 +159,12 @@ export type RoofConfig = {
export type AisleConfig = { export type AisleConfig = {
width: number; width: number;
height: number; height: number;
defaultColor: number; defaultColor: number;
} }
export type ZoneConfig = { export type ZoneConfig = {
defaultColor: string; defaultColor: string;
height: number;
color: string; color: string;
} }
@ -256,8 +245,8 @@ export const camPositionUpdateInterval: number = 200; // Interval for updating t
export const gridConfig: GridConfig = { export const gridConfig: GridConfig = {
size: 300, // Size of the grid size: 300, // Size of the grid
divisions: 75, // Number of divisions in the grid divisions: 75, // Number of divisions in the grid
primaryColor: "#d5d5d5", // Primary color of the grid primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid
secondaryColor: "#e3e3e3", // Secondary color of the grid secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid
position2D: [0, 0.1, 0], // Position of the grid in 2D view position2D: [0, 0.1, 0], // Position of the grid in 2D view
position3D: [0, -0.5, 0], // Position of the grid in 3D view position3D: [0, -0.5, 0], // Position of the grid in 3D view
@ -270,7 +259,7 @@ export const planeConfig: PlaneConfig = {
width: 300, // Width of the plane width: 300, // Width of the plane
height: 300, // Height of the plane height: 300, // Height of the plane
color: "#f3f3f3" // Color of the plane color: savedTheme === "dark" ? "#323232" : "#f3f3f3" // Color of the plane
} }
export const shadowConfig: ShadowConfig = { export const shadowConfig: ShadowConfig = {
@ -371,7 +360,8 @@ export const aisleConfig: AisleConfig = {
export const zoneConfig: ZoneConfig = { export const zoneConfig: ZoneConfig = {
defaultColor: "black", // Default color of the zones defaultColor: "black", // Default color of the zones
color: "blue" // Color of the zones height: 3,
color: "#8656DF" // Color of the zones
} }
export const columnConfig: ColumnConfig = { export const columnConfig: ColumnConfig = {

View File

@ -1,34 +1,31 @@
export { }; export { };
// Function to set the theme based on user preference or system default // Function to set the theme based on user preference or system default
function setTheme() { function setTheme() {
// Check for saved theme in localStorage
const savedTheme: string | null = localStorage.getItem('theme'); const savedTheme: string | null = localStorage.getItem('theme');
// If no saved theme, use system default preference
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');
// Set the theme on page load
document.documentElement.setAttribute('data-theme', defaultTheme); document.documentElement.setAttribute('data-theme', defaultTheme);
localStorage.setItem('theme', defaultTheme);
} }
// Call the function to set the theme // Function to toggle the theme
export function toggleTheme() {
const currentTheme: string | null = document.documentElement.getAttribute('data-theme');
const newTheme: string = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
}
// Initialize theme on page load
setTheme(); setTheme();
// Check if the toggle button exists // Example: Call toggleTheme() when a button is clicked
const toggleSwitch: Element | null = document.querySelector('.theme-switch'); const toggleSwitch: Element | null = document.querySelector('#theme-switch');
if (toggleSwitch) { if (toggleSwitch) {
toggleSwitch.addEventListener('click', () => { toggleSwitch.addEventListener('click', toggleTheme);
const currentTheme: string | null = document.documentElement.getAttribute('data-theme');
// Toggle between dark and light themes
const newTheme: string = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
// Save the new preference in localStorage
localStorage.setItem('theme', newTheme);
});
} else { } else {
console.warn("Theme switch button not found!"); console.warn("Theme switch button not found!");
} }