diff --git a/app/src/components/layout/sidebarRight/resourceManagement/hrm/assetManagement/AssetManagement.tsx b/app/src/components/layout/sidebarRight/resourceManagement/hrm/assetManagement/AssetManagement.tsx
index 463afe1..faa6015 100644
--- a/app/src/components/layout/sidebarRight/resourceManagement/hrm/assetManagement/AssetManagement.tsx
+++ b/app/src/components/layout/sidebarRight/resourceManagement/hrm/assetManagement/AssetManagement.tsx
@@ -125,7 +125,10 @@ const AssetManagement = () => {
{expandedAssetId === asset.id ?
-

+ <>
+
setExpandedAssetId(null)}>▾
+

+ >
:
}
@@ -167,7 +170,7 @@ const AssetManagement = () => {
- setExpandedAssetId(null)}>
+
handleAssetClick(asset.id)}>View in Scene
diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx
index e834f28..d5d49e4 100644
--- a/app/src/components/ui/Tools.tsx
+++ b/app/src/components/ui/Tools.tsx
@@ -36,6 +36,7 @@ import {
} from "../../store/visualization/useDroppedObjectsStore";
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../modules/builder/version/versionContext";
+import { MoveIcon, RotateIcon } from "../icons/ShortcutIcons";
// Utility component
const ToolButton = ({
@@ -65,12 +66,8 @@ const Tools: React.FC = () => {
const { isPlaying, setIsPlaying } = usePlayButtonStore();
const { showShortcuts } = useShortcutStore();
- const {
- activeTool,
- setActiveTool,
- setToolMode,
- setAddAction,
- } = useStoreHooks();
+ const { activeTool, setActiveTool, setToolMode, setAddAction } =
+ useStoreHooks();
const { setActiveSubTool, activeSubTool } = useActiveSubTool();
const { setSelectedWallItem } = useSelectedWallItem();
@@ -81,14 +78,15 @@ const Tools: React.FC = () => {
const { selectedZone } = useSelectedZoneStore();
const { floatingWidget } = useFloatingWidget();
const { widgets3D } = use3DWidget();
- const { visualizationSocket } = useSocketStore();
- const dropdownRef = useRef
(null);
- const [openDrop, setOpenDrop] = useState(false);
+ const { visualizationSocket } = useSocketStore();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
+ const dropdownRef = useRef(null);
+ const [openDrop, setOpenDrop] = useState(false);
+
// 1. Set UI toggles on initial render
useEffect(() => {
setToggleUI(
@@ -155,7 +153,7 @@ const Tools: React.FC = () => {
if (!is2D) setAddAction("Pillar");
break;
case "delete":
- is2D ? setToolMode('2D-Delete') : setToolMode('3D-Delete');
+ is2D ? setToolMode("2D-Delete") : setToolMode("3D-Delete");
break;
}
};
@@ -251,7 +249,7 @@ const Tools: React.FC = () => {
templates,
visualizationSocket,
projectId,
- versionId: selectedVersion?.versionId || ''
+ versionId: selectedVersion?.versionId || "",
})
}
/>
@@ -278,6 +276,10 @@ const Tools: React.FC = () => {
return FreeMoveIcon;
case "delete":
return DeleteIcon;
+ case "move":
+ return MoveIcon;
+ case "rotate":
+ return RotateIcon;
default:
return CursorIcon;
}
@@ -304,6 +306,10 @@ const Tools: React.FC = () => {
return ;
case "delete":
return ;
+ case "move":
+ return ;
+ case "rotate":
+ return ;
default:
return null;
}
@@ -362,6 +368,24 @@ const Tools: React.FC = () => {
)}
+ {activeModule !== "visualization" && (
+ <>
+
+
+ {["move", "rotate"].map((tool) => (
+ setActiveTool(tool)}
+ />
+ ))}
+
+ >
+ )}
+
{activeModule === "builder" && renderBuilderTools()}
{activeModule === "simulation" && renderSimulationTools()}
diff --git a/app/src/modules/scene/tools/measurementTool.tsx b/app/src/modules/scene/tools/measurementTool.tsx
index 1da41b3..4ca56fd 100644
--- a/app/src/modules/scene/tools/measurementTool.tsx
+++ b/app/src/modules/scene/tools/measurementTool.tsx
@@ -2,240 +2,188 @@ import * as THREE from "three";
import { useEffect, useRef, useState } from "react";
import { useThree, useFrame } from "@react-three/fiber";
import { useToolMode } from "../../../store/builder/store";
-import { Html } from "@react-three/drei";
+import { Html, Line } from "@react-three/drei";
const MeasurementTool = () => {
- const { gl, raycaster, pointer, camera, scene } = useThree();
- const { toolMode } = useToolMode();
+ const { gl, raycaster, pointer, camera, scene } = useThree();
+ const { toolMode } = useToolMode();
- const [points, setPoints] = useState([]);
- const [tubeGeometry, setTubeGeometry] = useState(
- null
- );
- const groupRef = useRef(null);
- const [startConePosition, setStartConePosition] =
- useState(null);
- const [endConePosition, setEndConePosition] = useState(
- null
- );
- const [startConeQuaternion, setStartConeQuaternion] = useState(
- new THREE.Quaternion()
- );
- const [endConeQuaternion, setEndConeQuaternion] = useState(
- new THREE.Quaternion()
- );
- const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
+ const [points, setPoints] = useState([]);
+ const [linePoints, setLinePoints] = useState(null);
+ const groupRef = useRef(null);
- const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1;
- const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4;
- const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0;
+ useEffect(() => {
+ const canvasElement = gl.domElement;
+ let drag = false;
+ let isLeftMouseDown = false;
- useEffect(() => {
- const canvasElement = gl.domElement;
- let drag = false;
- let isLeftMouseDown = false;
-
- const onMouseDown = () => {
- isLeftMouseDown = true;
- drag = false;
- };
-
- const onMouseUp = (evt: any) => {
- isLeftMouseDown = false;
- if (evt.button === 0 && !drag) {
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster
- .intersectObjects(scene.children, true)
- .filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.name.includes("agv-collider") &&
- !intersect.object.name.includes("zonePlane") &&
- !intersect.object.name.includes("SelectionGroup") &&
- !intersect.object.name.includes("selectionAssetGroup") &&
- !intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
- !intersect.object.name.includes("SelectionGroupBoundingBox") &&
- !intersect.object.name.includes("SelectionGroupBoundingLine") &&
- intersect.object.type !== "GridHelper"
- );
-
- if (intersects.length > 0) {
- const intersectionPoint = intersects[0].point.clone();
- if (points.length < 2) {
- setPoints([...points, intersectionPoint]);
- } else {
- setPoints([intersectionPoint]);
- }
- }
- }
- };
-
- const onMouseMove = () => {
- if (isLeftMouseDown) drag = true;
- };
-
- const onContextMenu = (evt: any) => {
- evt.preventDefault();
- if (!drag) {
- evt.preventDefault();
- setPoints([]);
- setTubeGeometry(null);
- }
- };
-
- if (toolMode === "MeasurementScale") {
- canvasElement.addEventListener("pointerdown", onMouseDown);
- canvasElement.addEventListener("pointermove", onMouseMove);
- canvasElement.addEventListener("pointerup", onMouseUp);
- canvasElement.addEventListener("contextmenu", onContextMenu);
- } else {
- resetMeasurement();
- setPoints([]);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onMouseDown);
- canvasElement.removeEventListener("pointermove", onMouseMove);
- canvasElement.removeEventListener("pointerup", onMouseUp);
- canvasElement.removeEventListener("contextmenu", onContextMenu);
- };
- }, [toolMode, camera, raycaster, pointer, scene, points]);
-
- useFrame(() => {
- if (points.length === 1) {
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster
- .intersectObjects(scene.children, true)
- .filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.name.includes("agv-collider") &&
- !intersect.object.name.includes("zonePlane") &&
- !intersect.object.name.includes("SelectionGroup") &&
- !intersect.object.name.includes("selectionAssetGroup") &&
- !intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
- !intersect.object.name.includes("SelectionGroupBoundingBox") &&
- !intersect.object.name.includes("SelectionGroupBoundingLine") &&
- intersect.object.type !== "GridHelper"
- );
-
- if (intersects.length > 0) {
- updateMeasurement(points[0], intersects[0].point);
- }
- } else if (points.length === 2) {
- updateMeasurement(points[0], points[1]);
- } else {
- resetMeasurement();
- }
- });
-
- const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
- const distance = start.distanceTo(end);
-
- const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS);
- const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS);
- const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT);
-
- setConeSize({ radius: coneRadius, height: coneHeight });
-
- const direction = new THREE.Vector3().subVectors(end, start).normalize();
-
- const offset = direction.clone().multiplyScalar(coneHeight * 0.5);
-
- let tubeStart = start.clone().add(offset);
- let tubeEnd = end.clone().sub(offset);
-
- tubeStart.y = Math.max(tubeStart.y, 0);
- tubeEnd.y = Math.max(tubeEnd.y, 0);
-
- const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
- setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));
-
- setStartConePosition(tubeStart);
- setEndConePosition(tubeEnd);
- setStartConeQuaternion(getArrowOrientation(start, end));
- setEndConeQuaternion(getArrowOrientation(end, start));
+ const onMouseDown = () => {
+ isLeftMouseDown = true;
+ drag = false;
};
- const resetMeasurement = () => {
- setTubeGeometry(null);
- setStartConePosition(null);
- setEndConePosition(null);
- };
+ const onMouseUp = (evt: any) => {
+ isLeftMouseDown = false;
+ if (evt.button === 0 && !drag) {
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster
+ .intersectObjects(scene.children, true)
+ .filter(
+ (intersect) =>
+ !intersect.object.name.includes("Roof") &&
+ !intersect.object.name.includes("MeasurementReference") &&
+ !intersect.object.name.includes("agv-collider") &&
+ !intersect.object.name.includes("zonePlane") &&
+ !intersect.object.name.includes("SelectionGroup") &&
+ !intersect.object.name.includes("selectionAssetGroup") &&
+ !intersect.object.name.includes(
+ "SelectionGroupBoundingBoxLine"
+ ) &&
+ !intersect.object.name.includes("SelectionGroupBoundingBox") &&
+ !intersect.object.name.includes("SelectionGroupBoundingLine") &&
+ intersect.object.type !== "GridHelper"
+ );
- const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
- const direction = new THREE.Vector3()
- .subVectors(end, start)
- .normalize()
- .negate();
- const quaternion = new THREE.Quaternion();
- quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
- return quaternion;
- };
-
- useEffect(() => {
- if (points.length === 2) {
- // console.log(points[0].distanceTo(points[1]));
+ if (intersects.length > 0) {
+ const intersectionPoint = intersects[0].point.clone();
+ if (points.length < 2) {
+ setPoints([...points, intersectionPoint]);
+ } else {
+ setPoints([intersectionPoint]);
+ }
}
- }, [points]);
+ }
+ };
- return (
-
- {startConePosition && (
-
-
-
-
- )}
- {endConePosition && (
-
-
-
-
- )}
- {tubeGeometry && (
-
-
-
- )}
+ const onMouseMove = () => {
+ if (isLeftMouseDown) drag = true;
+ };
- {startConePosition && endConePosition && (
-
-
- {(startConePosition.distanceTo(endConePosition) + (coneSize.height)).toFixed(2)} m
-
-
- )}
-
- );
+ const onContextMenu = (evt: any) => {
+ evt.preventDefault();
+ if (!drag) {
+ setPoints([]);
+ setLinePoints(null);
+ }
+ };
+
+ if (toolMode === "MeasurementScale") {
+ canvasElement.addEventListener("pointerdown", onMouseDown);
+ canvasElement.addEventListener("pointermove", onMouseMove);
+ canvasElement.addEventListener("pointerup", onMouseUp);
+ canvasElement.addEventListener("contextmenu", onContextMenu);
+ } else {
+ setPoints([]);
+ setLinePoints(null);
+ }
+
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onMouseDown);
+ canvasElement.removeEventListener("pointermove", onMouseMove);
+ canvasElement.removeEventListener("pointerup", onMouseUp);
+ canvasElement.removeEventListener("contextmenu", onContextMenu);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [toolMode, camera, raycaster, pointer, scene, points]);
+
+ useFrame(() => {
+ if (points.length === 1) {
+ // live preview for second point
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster
+ .intersectObjects(scene.children, true)
+ .filter(
+ (intersect) =>
+ !intersect.object.name.includes("Roof") &&
+ !intersect.object.name.includes("MeasurementReference") &&
+ !intersect.object.name.includes("agv-collider") &&
+ !intersect.object.name.includes("zonePlane") &&
+ !intersect.object.name.includes("SelectionGroup") &&
+ !intersect.object.name.includes("selectionAssetGroup") &&
+ !intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
+ !intersect.object.name.includes("SelectionGroupBoundingBox") &&
+ !intersect.object.name.includes("SelectionGroupBoundingLine") &&
+ intersect.object.type !== "GridHelper"
+ );
+
+ if (intersects.length > 0) {
+ const tempEnd = intersects[0].point.clone();
+ updateMeasurement(points[0], tempEnd);
+ }
+ } else if (points.length === 2) {
+ // second point already fixed
+ updateMeasurement(points[0], points[1]);
+ } else {
+ setLinePoints(null);
+ }
+ });
+
+ const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
+ setLinePoints([start.clone(), end.clone()]);
+ };
+
+ return (
+
+ {linePoints && (
+ <>
+ {/* Outline line */}
+
+
+ {/* Main line */}
+
+ >
+ )}
+
+ {points.map((point, index) => (
+
+
+
+ ))}
+
+ {linePoints && linePoints.length === 2 && (
+
+ {linePoints[0].distanceTo(linePoints[1]).toFixed(2)} m
+
+ )}
+
+ );
};
export default MeasurementTool;
diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss
index c07f11a..e01160d 100644
--- a/app/src/styles/components/tools.scss
+++ b/app/src/styles/components/tools.scss
@@ -31,6 +31,7 @@
}
.draw-tools,
+ .transform-tools,
.general-options,
.activeDropicon {
@include flex-center;
diff --git a/app/src/styles/layout/resourceManagement.scss b/app/src/styles/layout/resourceManagement.scss
index 400a98c..d62afe8 100644
--- a/app/src/styles/layout/resourceManagement.scss
+++ b/app/src/styles/layout/resourceManagement.scss
@@ -1,491 +1,700 @@
@use "../abstracts/variables" as *;
@use "../abstracts/mixins" as *;
-
-
.resourceManagement-container {
- .navigation-wrapper {
- @include flex-space-between;
- justify-content: space-around;
+ .navigation-wrapper {
+ @include flex-space-between;
+ justify-content: space-around;
- .navigation {
+ .navigation {
+ padding: 4px 12px;
+ border-radius: 20px;
+ text-wrap: nowrap;
+ margin: 6px 0;
+ cursor: pointer;
- padding: 4px 12px;
- border-radius: 20px;
- text-wrap: nowrap;
- margin: 6px 0;
- cursor: pointer;
+ &.active {
+ background: var(--background-color-button);
+ }
+ }
+ }
- &.active {
- background: var(--background-color-button);
- }
- }
+ .search-container {
+ position: relative;
+ padding: 4px 2px;
+ .search-wrapper {
+ padding: 0;
+
+ input {
+ padding-right: 85px;
+ }
}
- .search-container {
+ .select-catagory {
+ position: absolute;
+ top: 50%;
+ right: 8px;
+ transform: translate(0, -50%);
+ z-index: 10;
+
+ .regularDropdown-container {
+ padding: 2px 8px;
+ }
+ }
+ }
+
+ .category-wrapper {
+ display: flex;
+ gap: 12px;
+ width: 100%;
+ overflow: auto;
+ padding: 8px 10px;
+
+ .category {
+ text-wrap: nowrap;
+ position: relative;
+ cursor: pointer;
+ color: var(--text-disabled);
+
+ &.active {
+ color: var(--text-color);
+
+ &::after {
+ content: "";
+ position: absolute;
+ bottom: -6px;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ border-radius: 100px;
+ background: var(--background-color-button);
+ }
+ }
+ }
+ }
+
+ .assetManagement-wrapper {
+ max-height: calc(62vh - 12px);
+ overflow: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ margin-top: 7px;
+ // padding: 7px 2px;
+ }
+
+ // HRM
+ .hrm-container {
+ .analysis-wrapper {
+ border-radius: 20px;
+ padding: 16px;
+
+ display: flex;
+ flex-direction: column;
+ gap: 14px;
+
+ outline: 1px solid var(--border-color);
+ outline-offset: -1px;
+ background: var(--background-color);
+
+ &.active {
+ outline: 1px solid var(--Color-Hover, #ccacff);
+ }
+
+ header {
position: relative;
- padding: 4px 2px;
+ @include flex-space-between;
+ padding: 3px 0;
- .search-wrapper {
- padding: 0;
+ .user-details {
+ display: flex;
+ gap: 6px;
- input {
- padding-right: 85px;
- }
- }
-
- .select-catagory {
- position: absolute;
- top: 50%;
- right: 8px;
- transform: translate(0, -50%);
- z-index: 10;
-
- .regularDropdown-container {
- padding: 2px 8px;
- }
- }
- }
-
- .category-wrapper {
- display: flex;
- gap: 12px;
- width: 100%;
- overflow: auto;
- padding: 8px 10px;
-
- .category {
- text-wrap: nowrap;
+ .user-image-wrapper {
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background-color: #fff;
position: relative;
- cursor: pointer;
- color: var(--text-disabled);
- &.active {
- color: var(--text-color);
+ .status {
+ border-radius: 50%;
+ width: 6px;
+ height: 6px;
+ outline: 1px solid #2f2c32;
- &::after {
- content: "";
- position: absolute;
- bottom: -6px;
- left: 0;
- width: 100%;
- height: 2px;
- border-radius: 100px;
- background: var(--background-color-button);
- }
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ &.Active {
+ background-color: #44e5c6;
+ }
}
- }
- }
+ }
- .assetManagement-wrapper {
- max-height: calc(62vh - 12px);
- overflow: auto;
+ .details {
+ max-width: 144px;
+ .employee-id {
+ color: #b7b7c6;
+ font-size: $tiny;
+ }
+ }
+ }
+
+ .see-more {
+ padding: 4px 12px;
+ border-radius: 20px;
+ text-wrap: nowrap;
+ margin: 6px 0;
+ cursor: pointer;
+ background: var(--background-color-button);
+ }
+
+ &::after {
+ content: "";
+ position: absolute;
+ bottom: -7px;
+ left: 0;
+ width: 100%;
+ height: 1px;
+ background-color: #6f6f7a;
+ }
+ }
+
+ .content {
display: flex;
flex-direction: column;
- gap: 12px;
- margin-top: 7px;
- // padding: 7px 2px;
- }
+ gap: 4px;
- // HRM
- .hrm-container {
- .analysis-wrapper {
- border-radius: 20px;
- padding: 16px;
+ .task-info {
+ padding: 8px 0;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ .task-wrapper {
display: flex;
- flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+
+ .task-label {
+ display: flex;
+ align-items: center;
+ gap: 3px;
+
+ .label-text {
+ color: #b7b7c6;
+ }
+ }
+ }
+ }
+
+ .task-stats {
+ display: grid;
+ grid-template-columns: repeat(1, 1fr); // Two equal-width columns
+ gap: 4px;
+
+ .stat-item {
+ border-radius: 100px;
+ @include flex-space-between;
+ background: linear-gradient(
+ 162.53deg,
+ rgba(51, 51, 51, 0.7) 0%,
+ rgba(45, 36, 55, 0.7) 106.84%
+ );
+ border: 1px solid #ffffff0d;
+ padding: 6px;
+
+ .stat-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ }
+
+ span,
+ .stat-value {
+ font-size: 10px;
+ display: flex;
+ }
+ }
+ }
+
+ .location-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 6px 0;
+
+ .location-header {
+ display: flex;
+ gap: 6px;
+
+ .icon {
+ display: flex;
+ }
+
+ .header {
+ font-size: 12px;
+ color: #b7b7c6;
+ }
+ }
+ }
+
+ .task-actions {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr); // Two equal-width columns
+ gap: 4px;
+ margin-top: 3px;
+
+ button {
+ line-height: 133%;
+ font-size: 11px;
+ border: 1px solid var(--Linear-Border, #564b69);
+ border-radius: 100px;
+ padding: 4px 0;
+
+ &:last-child {
+ background-color: #cc2c1e;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // ASSET MANAGEMENT
+ .assetManagement-container {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+
+ .assetManagement-card-wrapper {
+ padding: 16px;
+ border: 1px solid #564b69;
+ border-radius: 20px;
+ gap: 10px;
+
+ header {
+ border-bottom: 1px solid #595965;
+ padding-bottom: 8px;
+
+ .header-wrapper {
+ display: flex;
+ gap: 8px;
+
+ .icon {
+ min-width: 28px;
+ height: 28px;
+ border-radius: 7px;
+ @include flex-center;
+ background: var(--background-color-button);
+ }
+
+ .asset-image {
+ width: 114px;
+ height: 112px;
+ border-radius: 15.2px;
+ object-fit: cover;
+ }
+
+ .asset-details-container {
+ width: 100%;
+ @include flex-space-between;
+
+ .asset-details {
+ display: flex;
+ gap: 4px;
+ width: 100%;
+ max-width: 160px;
+ .input-value {
+ width: fit-content;
+ }
+ .asset-model {
+ color: var(--text-disabled);
+ display: none;
+ }
+ }
+ }
+
+ .asset-status-wrapper {
+ padding: 4px 8px;
+ border: 1px solid var(--text-color-dark, #f3f3fdd9);
+ border-radius: 100px;
+ @include flex-space-between;
+ gap: 4px;
+
+ .indication {
+ width: 6px;
+ height: 6px;
+ border-radius: 100%;
+
+ &.Online {
+ background-color: #44e5c6;
+ }
+ }
+
+ .status {
+ font-size: $small;
+ }
+ }
+ }
+ }
+
+ .asset-contents {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+
+ .asset-wrapper {
+ @include flex-space-between;
+ padding: 6px 0;
+ gap: 20px;
+
+ .key-wrapper,
+ .viewMore {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+
+ .icon {
+ @include flex-center;
+ }
+ }
+
+ .viewMore {
+ padding: 8px;
+ border-radius: 100px;
+ background: var(--background-color-button);
+ cursor: pointer;
+ }
+
+ .progress-wrapper {
+ flex: 1;
+ @include flex-space-between;
+ gap: 4px;
+
+ .progress-bar {
+ width: 100%;
+ height: 5px;
+ border-radius: 20px;
+ background-color: #6f6f7a;
+ position: relative;
+
+ .filled-value {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 10px;
+ background-color: #ccacff;
+ border-radius: 20px;
+ }
+ }
+ }
+ }
+ }
+
+ .asset-estimate {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ &__label {
+ color: #b7b7c6;
+ font-size: 14px;
+ }
+
+ &__value {
+ font-weight: 500;
+ font-size: 16px;
+ }
+
+ &__unit-cost {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ &__breakdown {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ gap: 2px;
+ }
+
+ &__view-button {
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+ background-color: var(--background-color-button);
+ border-radius: 20px;
+ padding: 8px 0;
+ }
+
+ &__view-text {
+ font-weight: 500;
+ // color: #4A4AFF;
+ }
+ }
+
+ &.openViewMore {
+ outline-offset: -1px;
+ outline: 1px solid var(--Color-Hover, #ccacff);
+
+ header {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+
+ .header-wrapper {
gap: 14px;
- outline: 1px solid var(--border-color);
- outline-offset: -1px;
- background: var(--background-color);
+ .asset-details-container {
+ flex-direction: column;
+ align-items: start;
+ justify-content: start;
- &.active {
- outline: 1px solid var(--Color-Hover, #CCACFF);
- }
-
- header {
- position: relative;
- @include flex-space-between;
- padding: 3px 0;
-
- .user-details {
- display: flex;
- gap: 6px;
-
- .user-image-wrapper {
- width: 28px;
- height: 28px;
- border-radius: 50%;
- background-color: #fff;
- position: relative;
-
- .status {
- border-radius: 50%;
- width: 6px;
- height: 6px;
- outline: 1px solid #2F2C32;
-
- position: absolute;
- bottom: 0;
- right: 0;
-
- &.Active {
- background-color: #44E5C6;
- }
- }
- }
-
- .details {
- .employee-id {
- color: #B7B7C6;
- font-size: $tiny;
-
- }
- }
- }
-
- .see-more {
-
- padding: 4px 12px;
- border-radius: 20px;
- text-wrap: nowrap;
- margin: 6px 0;
- cursor: pointer;
- background: var(--background-color-button);
- }
-
- &::after {
- content: "";
- position: absolute;
- bottom: -7px;
- left: 0;
- width: 100%;
- height: 1px;
- background-color: #6F6F7A;
- }
- }
-
- .content {
+ .asset-details {
display: flex;
flex-direction: column;
gap: 4px;
-
- .task-info {
- padding: 8px 0;
- display: flex;
- flex-direction: column;
- gap: 6px;
-
- .task-wrapper {
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- .task-label {
- display: flex;
- align-items: center;
- gap: 3px;
-
- .label-text {
- color: #B7B7C6;
- }
- }
- }
- }
-
- .task-stats {
- display: grid;
- grid-template-columns: repeat(1, 1fr); // Two equal-width columns
- gap: 4px;
-
- .stat-item {
- border-radius: 100px;
- @include flex-space-between;
- background: linear-gradient(162.53deg,
- rgba(51, 51, 51, 0.7) 0%,
- rgba(45, 36, 55, 0.7) 106.84%);
- border: 1px solid #FFFFFF0D;
- padding: 6px;
-
- .stat-wrapper {
- display: flex;
- align-items: center;
- gap: 4px;
- }
-
- span,
- .stat-value {
- font-size: 10px;
- display: flex;
- }
- }
- }
-
- .location-wrapper {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 6px 0;
-
- .location-header {
- display: flex;
- gap: 6px;
-
- .icon {
- display: flex;
- }
-
- .header {
- font-size: 12px;
- color: #B7B7C6;
- }
- }
- }
-
- .task-actions {
- display: grid;
- grid-template-columns: repeat(2, 1fr); // Two equal-width columns
- gap: 4px;
- margin-top: 3px;
-
- button {
- line-height: 133%;
- font-size: 11px;
- border: 1px solid var(--Linear-Border, #564B69);
- border-radius: 100px;
- padding: 4px 0;
-
- &:last-child {
- background-color: #CC2C1E;
- }
- }
+ max-width: 144px;
+ .input-value {
+ text-wrap: wrap;
+ font-size: 1rem;
}
+ }
+ .asset-status-wrapper {
+ margin-top: 8px;
+ }
}
+ }
}
+ }
+ }
+ }
+}
+
+// ASSET MANAGEMENT
+.assetManagement-container {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ position: relative;
+
+ .assetManagement-card-wrapper {
+ padding: 16px;
+ border: 1px solid #564b69;
+ border-radius: 20px;
+ gap: 10px;
+ position: relative;
+
+ header {
+ border-bottom: 1px solid #595965;
+ padding-bottom: 8px;
+
+ .header-wrapper {
+ display: flex;
+ gap: 8px;
+
+ .icon {
+ min-width: 28px;
+ height: 28px;
+ border-radius: 7px;
+ @include flex-center;
+ background: var(--background-color-button);
+ }
+
+ .drop-icon {
+ position: absolute;
+ top: 18px;
+ right: 16px;
+ cursor: pointer;
+ }
+
+ .asset-image {
+ width: 114px;
+ height: 112px;
+ border-radius: 15.2px;
+ object-fit: cover;
+ }
+
+ .asset-details-container {
+ width: 100%;
+ @include flex-space-between;
+
+ .asset-details {
+ // .asset-name{
+ // overflow: hidden;
+ // }
+ .asset-model {
+ color: var(--text-disabled);
+ }
+ }
+ }
+
+ .asset-status-wrapper {
+ padding: 4px 8px;
+ border: 1px solid var(--text-color-dark, #f3f3fdd9);
+ border-radius: 100px;
+ @include flex-space-between;
+ gap: 4px;
+
+ .indication {
+ width: 6px;
+ height: 6px;
+ border-radius: 100%;
+
+ &.Online {
+ background-color: #44e5c6;
+ }
+ }
+
+ .status {
+ font-size: $small;
+ }
+ }
+ }
}
- // ASSET MANAGEMENT
- .assetManagement-container {
+ .asset-contents {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+
+ .asset-wrapper {
+ @include flex-space-between;
+ padding: 6px 0;
+ gap: 20px;
+
+ .key-wrapper,
+ .viewMore {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+
+ .icon {
+ @include flex-center;
+ }
+ }
+
+ .viewMore {
+ padding: 8px;
+ border-radius: 100px;
+ background: var(--background-color-button);
+ cursor: pointer;
+ }
+
+ .progress-wrapper {
+ flex: 1;
+ @include flex-space-between;
+ gap: 4px;
+
+ .progress-bar {
+ width: 100%;
+ height: 5px;
+ border-radius: 20px;
+ background-color: #6f6f7a;
+ position: relative;
+
+ .filled-value {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 10px;
+ background-color: #ccacff;
+ border-radius: 20px;
+ }
+ }
+ }
+ }
+ }
+
+ .asset-estimate {
+ margin-top: 5px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ &__label {
+ color: #b7b7c6;
+ font-size: 14px;
+ }
+
+ &__value {
+ font-weight: 500;
+ font-size: 16px;
+ }
+
+ &__unit-cost {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ &__breakdown {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ gap: 2px;
+ }
+
+ &__view-button {
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+ background-color: var(--background-color-button);
+ border-radius: 20px;
+ padding: 8px 0;
+ }
+
+ &__view-text {
+ font-weight: 500;
+ // color: #4A4AFF;
+ }
+ }
+
+ &.openViewMore {
+ outline-offset: -1px;
+ outline: 1px solid var(--Color-Hover, #ccacff);
+
+ header {
display: flex;
flex-direction: column;
gap: 6px;
- .assetManagement-card-wrapper {
- padding: 16px;
- border: 1px solid #564B69;
- border-radius: 20px;
- gap: 10px;
+ .header-wrapper {
+ gap: 20px;
+ .asset-details-container {
+ flex-direction: column;
+ align-items: start;
+ justify-content: center;
+ .asset-details {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
- header {
- border-bottom: 1px solid #595965;
- padding-bottom: 8px;
-
-
- .header-wrapper {
- display: flex;
- gap: 8px;
-
- .icon {
- min-width: 28px;
- height: 28px;
- border-radius: 7px;
- @include flex-center;
- background: var(--background-color-button);
- }
-
- .asset-image {
- width: 114px;
- height: 112px;
- border-radius: 15.2px;
- object-fit: cover;
- }
-
- .asset-details-container {
- width: 100%;
- @include flex-space-between;
-
- .asset-details {
-
- // .asset-name{
- // overflow: hidden;
- // }
- .asset-model {
- color: var(--text-disabled);
-
- }
- }
- }
-
- .asset-status-wrapper {
- padding: 4px 8px;
- border: 1px solid var(--text-color-dark, #F3F3FDD9);
- border-radius: 100px;
- @include flex-space-between;
- gap: 4px;
-
- .indication {
- width: 6px;
- height: 6px;
- border-radius: 100%;
-
- &.Online {
- background-color: #44E5C6;
- }
- }
-
- .status {
- font-size: $small;
- }
- }
- }
+ .asset-name {
+ font-size: 16px;
+ }
}
- .asset-contents {
- display: flex;
- flex-direction: column;
- gap: 3px;
-
- .asset-wrapper {
- @include flex-space-between;
- padding: 6px 0;
- gap: 20px;
-
- .key-wrapper,
- .viewMore {
- display: flex;
- align-items: center;
- gap: 6px;
-
- .icon {
- @include flex-center;
- }
- }
-
- .viewMore {
- padding: 8px;
- border-radius: 100px;
- background: var(--background-color-button);
- cursor: pointer;
- }
-
- .progress-wrapper {
- flex: 1;
- @include flex-space-between;
- gap: 4px;
-
- .progress-bar {
- width: 100%;
- height: 5px;
- border-radius: 20px;
- background-color: #6F6F7A;
- position: relative;
-
- .filled-value {
- position: absolute;
- top: 0;
- left: 0;
- height: 100%;
- width: 10px;
- background-color: #CCACFF;
- border-radius: 20px;
- }
- }
- }
- }
+ .asset-status-wrapper {
+ margin-top: 4px;
}
-
- .asset-estimate {
- display: flex;
- flex-direction: column;
- gap: 10px;
-
- &__label {
- color: #B7B7C6;
- font-size: 14px;
- }
-
- &__value {
- font-weight: 500;
- font-size: 16px;
- }
-
- &__unit-cost {
- display: flex;
- flex-direction: column;
- gap: 4px;
- }
-
- &__breakdown {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- gap: 2px;
- }
-
- &__view-button {
- cursor: pointer;
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 4px;
- background-color: var(--background-color-button);
- border-radius: 20px;
- padding: 8px 0;
- }
-
- &__view-text {
- font-weight: 500;
- // color: #4A4AFF;
- }
- }
-
- &.openViewMore {
- outline-offset: -1px;
- outline: 1px solid var(--Color-Hover, #CCACFF);
-
- header {
- display: flex;
- flex-direction: column;
- gap: 6px;
-
- .header-wrapper {
-
- gap: 20px;
-
- .asset-details-container {
- flex-direction: column;
- align-items: start;
- justify-content: center;
-
- .asset-details {
- display: flex;
- flex-direction: column;
- gap: 4px;
-
- .asset-name {
- font-size: 16px;
- }
- }
-
- .asset-status-wrapper {
- margin-top: 4px;
- }
- }
- }
- }
-
-
-
- }
-
+ }
}
+ }
}
-
-}
\ No newline at end of file
+ }
+}
diff --git a/app/src/styles/scene/scene.scss b/app/src/styles/scene/scene.scss
index 6358c81..dee2536 100644
--- a/app/src/styles/scene/scene.scss
+++ b/app/src/styles/scene/scene.scss
@@ -130,15 +130,25 @@
svg {
display: none;
}
- .c-jiwtRJ{
+ .c-jiwtRJ {
align-items: center;
}
}
-.stats{
+.stats {
top: auto !important;
bottom: 36px !important;
left: 12px !important;
border-radius: 6px;
overflow: hidden;
}
+
+.measurement-point {
+ height: 12px;
+ width: 12px;
+ border-radius: 50%;
+ background: #b18ef1;
+ outline: 2px solid black;
+ outline-offset: -1px;
+ transform: translate(-50%, -50%);
+}