Merge branch 'main' into v2

This commit is contained in:
Jerald-Golden-B 2025-05-15 09:44:40 +05:30
commit 243a2e7606
12 changed files with 153 additions and 95 deletions

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef } from "react";
import React from "react";
import { HelpIcon } from "../icons/DashboardIcon";
import { useLogger } from "../ui/log/LoggerContext";
import { GetLogIcon } from "./getLogIcons";
@ -16,35 +16,14 @@ const Footer: React.FC = () => {
const { logs, setIsLogListVisible } = useLogger();
const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
const { isPlaying } = usePlayButtonStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
// Listen for Ctrl + Shift + ?
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (
e.ctrlKey &&
e.shiftKey &&
(e.key === "?" || e.key === "/") // for some keyboards ? and / share the same key
) {
e.preventDefault();
setShowShortcuts(!showShortcuts); // toggle visibility directly
}
if (e.key === "Escape") {
setShowShortcuts(false);
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [showShortcuts, setShowShortcuts]);
OuterClick({
contextClassName: ["shortcut-helper-overlay"],
setMenuVisible: () => setShowShortcuts(false),
});
return (
<div className="footer-container">
<div className="footer-wrapper">

View File

@ -0,0 +1,31 @@
import React from "react";
import useLayoutStore from "../../store/builder/uselayoutStore";
const SelectFloorPlan: React.FC = () => {
const { currentLayout, setLayout } = useLayoutStore();
return (
<div className="select-floorplane-wrapper">
Preset Layouts
<div className="presets-container">
<button
className={`preset ${currentLayout === "layout1" ? "active" : ""}`}
onClick={() => {
setLayout("layout1");
}}
>
Preset 1
</button>
<button
className={`preset ${currentLayout === "layout2" ? "active" : ""}`}
onClick={() => {
setLayout("layout2");
}}
>
Preset 2
</button>
</div>
</div>
);
};
export default SelectFloorPlan;

View File

@ -1,15 +1,14 @@
import React, { useEffect } from 'react';
import { useRoomsState, useToggleView } from '../../../store/builder/store';
import { computeArea } from '../functions/computeArea';
import { Html } from '@react-three/drei';
import { useRoomsState, useToggleView } from "../../../store/builder/store";
import { computeArea } from "../functions/computeArea";
import { Html } from "@react-three/drei";
import * as CONSTANTS from "../../../types/world/worldConstants";
import * as turf from '@turf/turf';
import * as THREE from "three"
import * as turf from "@turf/turf";
import * as THREE from "three";
const CalculateAreaGroup = () => {
const { roomsState } = useRoomsState();
const { toggleView } = useToggleView();
const savedTheme: string | null = localStorage.getItem('theme');
const savedTheme: string | null = localStorage.getItem("theme");
return (
<group name="roomArea" visible={toggleView}>
@ -19,9 +18,9 @@ const CalculateAreaGroup = () => {
const coordinates = room.coordinates;
if (!coordinates || coordinates.length < 3) return null;
const yPos = (room.layer || 0) * CONSTANTS.zoneConfig.height;
const coords2D = coordinates.map((p: any) => new THREE.Vector2(p.position.x, p.position.z));
// console.log('coords2D: ', coords2D);
const coords2D = coordinates.map(
(p: any) => new THREE.Vector2(p.position.x, p.position.z)
);
if (!coords2D[0].equals(coords2D[coords2D.length - 1])) {
coords2D.push(coords2D[0]);
@ -37,7 +36,7 @@ const CalculateAreaGroup = () => {
geometry.rotateX(Math.PI / 2);
const material = new THREE.MeshBasicMaterial({
color: savedTheme === "dark" ? "#d2baff" : '#6f42c1',
color: savedTheme === "dark" ? "#d2baff" : "#6f42c1",
side: THREE.DoubleSide,
transparent: true,
opacity: 0.4,
@ -46,7 +45,11 @@ const CalculateAreaGroup = () => {
return (
<group key={`roomFill-${index}`}>
<mesh geometry={geometry} material={material} position={[0, yPos, 0]} />
<mesh
geometry={geometry}
material={material}
position={[0, 0.12, 0]}
/>
</group>
);
})}
@ -58,7 +61,10 @@ const CalculateAreaGroup = () => {
if (!coordinates || coordinates.length < 3) return null;
let coords2D = coordinates.map((p: any) => [p.position.x, p.position.z]);
let coords2D = coordinates.map((p: any) => [
p.position.x,
p.position.z,
]);
const first = coords2D[0];
const last = coords2D[coords2D.length - 1];
@ -69,7 +75,10 @@ const CalculateAreaGroup = () => {
const polygon = turf.polygon([coords2D]);
const center2D = turf.center(polygon).geometry.coordinates;
const sumY = coordinates.reduce((sum: number, p: any) => sum + p.position.y, 0);
const sumY = coordinates.reduce(
(sum: number, p: any) => sum + p.position.y,
0
);
const avgY = sumY / coordinates.length;
const area = computeArea(room, "rooms");
@ -100,6 +109,6 @@ const CalculateAreaGroup = () => {
})}
</group>
);
}
};
export default CalculateAreaGroup;

View File

@ -363,6 +363,10 @@ const FloorItemsGroup = ({
if (!event.dataTransfer?.files[0]) return;
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') {
state.pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
state.pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
addAssetModel(
raycaster,
state.camera,

View File

@ -11,25 +11,24 @@ const modelPaths: Record<string, string> = {
};
function LayoutModel() {
const { toggleView } = useToggleView();
const { currentLayout } = useLayoutStore();
if (!currentLayout) return null;
const { toggleView } = useToggleView();
const { currentLayout } = useLayoutStore();
const path = modelPaths[currentLayout];
const gltf = useGLTF(path);
const cloned = useMemo(() => gltf?.scene?.clone(), [gltf]);
// Always call the hook, but ensure it has a valid fallback
const path = currentLayout ? modelPaths[currentLayout] : modelPaths.layout1;
return (
<>
{toggleView &&
<group position={[0,0,0]} scale={[0,0,0]} dispose={null}>
<primitive
object={cloned}
/>
</group>
}
</>
);
// Explicitly cast the return type to ensure it's not an array
const gltf = useGLTF(path) as any;
const cloned = useMemo(() => gltf.scene.clone(), [gltf]);
if (!currentLayout || !toggleView) return null;
return (
<group position={[0, 0, 0]} dispose={null}>
<primitive object={cloned} />
</group>
);
}
export default LayoutModel;
export default LayoutModel;

View File

@ -31,6 +31,7 @@ import { useLogger } from "../components/ui/log/LoggerContext";
import RenderOverlay from "../components/templates/Overlay";
import LogList from "../components/ui/log/LogList";
import Footer from "../components/footer/Footer";
import SelectFloorPlan from "../components/temporary/SelectFloorPlan";
const Project: React.FC = () => {
let navigate = useNavigate();
@ -98,6 +99,8 @@ const Project: React.FC = () => {
{activeModule === "market" && <MarketPlace />}
{activeModule !== "market" && <Tools />}
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
{/* remove this later */}
{activeModule === "builder" && !toggleThreeD && <SelectFloorPlan />}
</>
)}
<div

View File

@ -1,6 +1,7 @@
import * as THREE from "three";
import { create } from "zustand";
import { io } from "socket.io-client";
import * as CONSTANTS from '../../types/world/worldConstants';
export const useSocketStore = create<any>((set: any, get: any) => ({
socket: null,
@ -386,8 +387,8 @@ export const useLimitDistance = create<any>((set: any) => ({
}));
export const useTileDistance = create<any>((set: any) => ({
gridValue: { size: 300, divisions: 75 },
planeValue: { height: 300, width: 300 },
gridValue: { size: CONSTANTS.gridConfig.size, divisions: CONSTANTS.gridConfig.divisions },
planeValue: { height: CONSTANTS.planeConfig.height, width: CONSTANTS.planeConfig.width },
setGridValue: (value: any) =>
set((state: any) => ({
@ -428,26 +429,26 @@ export const useZoneAssetId = create<ZoneAssetState>((set) => ({
// version visible hidden
interface VersionHistoryState {
viewVersionHistory: boolean;
setVersionHistory: (value: boolean) => void;
viewVersionHistory: boolean;
setVersionHistory: (value: boolean) => void;
}
const useVersionHistoryStore = create<VersionHistoryState>((set) => ({
viewVersionHistory: false,
setVersionHistory: (value) => set({ viewVersionHistory: value }),
viewVersionHistory: false,
setVersionHistory: (value) => set({ viewVersionHistory: value }),
}));
export default useVersionHistoryStore;
interface ShortcutStore {
showShortcuts: boolean;
setShowShortcuts: (value: boolean) => void;
toggleShortcuts: () => void;
showShortcuts: boolean;
setShowShortcuts: (value: boolean) => void;
toggleShortcuts: () => void;
}
export const useShortcutStore = create<ShortcutStore>((set) => ({
showShortcuts: false,
setShowShortcuts: (value) => set({ showShortcuts: value }),
toggleShortcuts: () =>
set((state) => ({ showShortcuts: !state.showShortcuts })),
showShortcuts: false,
setShowShortcuts: (value) => set({ showShortcuts: value }),
toggleShortcuts: () =>
set((state) => ({ showShortcuts: !state.showShortcuts })),
}));

View File

@ -42,17 +42,16 @@
text-align: center;
padding: 4px 8px;
border-radius: #{$border-radius-large};
.value {
width: 100%;
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
text-align: start;
}
.zone-header {
@include flex-center;
.value {
width: 100%;
text-align: start;
max-width: 180px;
}
}
.options-container {
@include flex-center;
gap: 6px;
@ -74,7 +73,9 @@
&:hover {
cursor: pointer;
background: var(--highlight-accent-color);
.list-item {
background: var(--highlight-accent-color);
}
}
}
@ -83,4 +84,4 @@
margin-left: 20px;
}
}
}

View File

@ -19,7 +19,7 @@
border-radius: #{$border-radius-medium};
box-shadow: var(--box-shadow-light);
}
.area{
.area {
background: #008cff;
}
}
@ -27,3 +27,34 @@
.pointer-none {
pointer-events: none;
}
// temp
.select-floorplane-wrapper {
position: absolute;
@include flex-center;
gap: 12px;
top: 0;
left: 50%;
padding: 8px;
padding-left: 14px;
background: var(--background-color);
backdrop-filter: blur(12px);
border-radius: #{$border-radius-large};
outline: 1px solid var(--border-color);
transform: translate(-50%, 12px);
z-index: 100;
.presets-container {
@include flex-center;
gap: 4px;
.preset {
background: var(--background-color);
padding: 2px 8px;
border-radius: #{$border-radius-large};
outline: 1px solid var(--border-color);
}
.active{
background: var(--background-color-accent);
color: var(--text-button-color);
}
}
}

View File

@ -227,22 +227,10 @@ export const twoDimension: TwoDimension = {
rightMouse: 0, // Mouse button for no action
};
export const threeDimension: ThreeDimension = {
defaultPosition: [0, 40, 30], // Default position of the camera
defaultTarget: [0, 0, 0], // Default target of the camera
defaultRotation: [0, 0, 0], // Default rotation of the camera
defaultAzimuth: 0, // Default azimuth of the camera
boundaryBottom: [-150, 0, -150], // Bottom boundary of the camera movement
boundaryTop: [150, 100, 150], // Top boundary of the camera movement
minDistance: 1, // Minimum distance from the target
leftMouse: 2, // Mouse button for panning
rightMouse: 1, // Mouse button for rotation
};
export const camPositionUpdateInterval: number = 200; // Interval for updating the camera position
export const gridConfig: GridConfig = {
size: 300, // Size of the grid
size: 150, // Size of the grid
divisions: 75, // Number of divisions in the grid
primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid
secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid
@ -251,13 +239,25 @@ export const gridConfig: GridConfig = {
position3D: [0, -0.5, 0], // Position of the grid in 3D view
};
export const threeDimension: ThreeDimension = {
defaultPosition: [0, 40, 30], // Default position of the camera
defaultTarget: [0, 0, 0], // Default target of the camera
defaultRotation: [0, 0, 0], // Default rotation of the camera
defaultAzimuth: 0, // Default azimuth of the camera
boundaryBottom: [-gridConfig.size / 2, 0, -gridConfig.size / 2], // Bottom boundary of the camera movement
boundaryTop: [gridConfig.size / 2, 100, gridConfig.size / 2], // Top boundary of the camera movement
minDistance: 1, // Minimum distance from the target
leftMouse: 2, // Mouse button for panning
rightMouse: 1, // Mouse button for rotation
};
export const planeConfig: PlaneConfig = {
position2D: [0, -0.5, 0], // Position of the plane
position3D: [0, -0.65, 0], // Position of the plane
rotation: -Math.PI / 2, // Rotation of the plane
width: 300, // Width of the plane
height: 300, // Height of the plane
width: 150, // Width of the plane
height: 150, // Height of the plane
color: savedTheme === "dark" ? "#323232" : "#f3f3f3", // Color of the plane
};