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%); +}