Merge branch 'main' into v2
This commit is contained in:
commit
243a2e7606
Binary file not shown.
Binary file not shown.
|
@ -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">
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 })),
|
||||
}));
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue