diff --git a/app/src/components/layout/sidebarLeft/Header.tsx b/app/src/components/layout/sidebarLeft/Header.tsx index 6c2a8f2..70668af 100644 --- a/app/src/components/layout/sidebarLeft/Header.tsx +++ b/app/src/components/layout/sidebarLeft/Header.tsx @@ -28,7 +28,7 @@ const Header: React.FC = () => { } }} > -
{toggleUI ? "Hide" : "Show"} sidebar (ctrl + .)
+
{toggleUI ? "Hide" : "Show"} sidebar (ctrl + \)
diff --git a/app/src/components/ui/ModuleToggle.tsx b/app/src/components/ui/ModuleToggle.tsx index 053e251..a1583e1 100644 --- a/app/src/components/ui/ModuleToggle.tsx +++ b/app/src/components/ui/ModuleToggle.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React from "react"; import useModuleStore from "../../store/useModuleStore"; import { BuilderIcon, @@ -14,45 +14,60 @@ const ModuleToggle: React.FC = () => { return (
-
{ setActiveModule("builder"); - setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true) + setToggleUI( + localStorage.getItem("navBarUi") + ? localStorage.getItem("navBarUi") === "true" + : true + ); }} >
Builder
-
-
+
-
+
-
+
Market Place
-
+ ); }; diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index 0d93d72..2a77303 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -103,10 +103,9 @@ const DropDownList: React.FC = ({ return (
-
- + {/* eslint-disable-next-line */} +
+
{value}
{showFocusIcon && (
diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index ac49c8d..6ef8d2f 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -44,7 +44,7 @@ const SimulationPlayer: React.FC = () => { setReset(false); }, 0) } - }, [isReset]) + }, [isReset, setReset]) // Button functions const handleReset = () => { diff --git a/app/src/modules/collaboration/camera/collabCams.tsx b/app/src/modules/collaboration/camera/collabCams.tsx index d4bc69e..0b01af1 100644 --- a/app/src/modules/collaboration/camera/collabCams.tsx +++ b/app/src/modules/collaboration/camera/collabCams.tsx @@ -12,6 +12,7 @@ import CollabUserIcon from "./collabUserIcon"; import useModuleStore from "../../../store/useModuleStore"; import { getAvatarColor } from "../functions/getAvatarColor"; import { useSelectedUserStore } from "../../../store/useCollabStore"; +import { opacity } from "html2canvas/dist/types/css/property-descriptors/opacity"; const CamModelsGroup = () => { const navigate = useNavigate(); @@ -277,6 +278,10 @@ const CamModelsGroup = () => { textAlign: "center", fontFamily: "Arial, sans-serif", display: `${activeModule !== "visualization" ? "" : "none"}`, + opacity: `${ + selectedUser?.name !== cam.userData.userName ? 1 : 0 + }`, + transition: "opacity .2s ease", }} position={[-0.015, 0, 0.7]} > diff --git a/app/src/modules/scene/camera/camMode.tsx b/app/src/modules/scene/camera/camMode.tsx index d216ee1..0a0f954 100644 --- a/app/src/modules/scene/camera/camMode.tsx +++ b/app/src/modules/scene/camera/camMode.tsx @@ -19,12 +19,10 @@ const CamMode: React.FC = () => { const handlePointerLockChange = async () => { if (document.pointerLockElement && !toggleView) { // Pointer is locked - } else { + } else if (camMode === "FirstPerson" && !toggleView) { // Pointer is unlocked - if (camMode === "FirstPerson" && !toggleView) { - setCamMode("ThirdPerson"); - await switchToThirdPerson(state.controls, state.camera); - } + setCamMode("ThirdPerson"); + await switchToThirdPerson(state.controls, state.camera); } }; diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index cf3119a..16a1495 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -130,7 +130,7 @@ const Project: React.FC = () => { )} - {activeModule != "market" &&
} + {activeModule !== "market" && !selectedUser &&
}
); }; diff --git a/app/src/styles/components/templates.scss b/app/src/styles/components/templates.scss index a71354c..eea4354 100644 --- a/app/src/styles/components/templates.scss +++ b/app/src/styles/components/templates.scss @@ -7,7 +7,7 @@ top: 0; left: 0; outline: 8px solid var(--user-color); - outline-offset: -3px; + outline-offset: -4px; border-radius: #{$border-radius-xlarge}; .follower-name { diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 52877b9..a08834c 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -1,7 +1,4 @@ -// Importing React and useEffect from React library import React, { useEffect } from "react"; - -// Importing the necessary hooks and types from the application's state management stores import useModuleStore, { useThreeDStore } from "../../store/useModuleStore"; import useToggleStore from "../../store/useUIToggleStore"; import { @@ -14,185 +11,141 @@ import { useToolMode, } from "../../store/store"; import { usePlayButtonStore } from "../../store/usePlayButtonStore"; - -// Utility function to detect modifier keys (Ctrl, Alt, Shift) and key combinations import { detectModifierKeys } from "./detectModifierKeys"; -// KeyPressListener component to handle global keyboard shortcuts const KeyPressListener: React.FC = () => { - // Accessing state and actions from different stores - const { activeModule, setActiveModule } = useModuleStore(); // Module management (e.g., builder, simulation, visualization) - const { setActiveSubTool } = useActiveSubTool(); // Sub-tool management - const { toggleUI, setToggleUI } = useToggleStore(); // UI visibility toggle - const { setToggleThreeD } = useThreeDStore(); // 3D view toggle - const { setToolMode } = useToolMode(); // Tool mode management - const { setIsPlaying } = usePlayButtonStore(); // Play button state management + const { activeModule, setActiveModule } = useModuleStore(); + const { setActiveSubTool } = useActiveSubTool(); + const { toggleUI, setToggleUI } = useToggleStore(); + const { setToggleThreeD } = useThreeDStore(); + const { setToolMode } = useToolMode(); + const { setIsPlaying } = usePlayButtonStore(); + const { toggleView, setToggleView } = useToggleView(); + const { setDeleteTool } = useDeleteTool(); + const { setAddAction } = useAddAction(); + const { setSelectedWallItem } = useSelectedWallItem(); + const { setActiveTool } = useActiveTool(); - // Wall and tool-related actions - const { toggleView, setToggleView } = useToggleView(); // 2D/3D toggle state - const { setDeleteTool } = useDeleteTool(); // Delete tool action - const { setAddAction } = useAddAction(); // Add action management - const { setSelectedWallItem } = useSelectedWallItem(); // Selected wall item management - const { setActiveTool } = useActiveTool(); // Active tool management + const isTextInput = (element: Element | null): boolean => + element instanceof HTMLInputElement || + element instanceof HTMLTextAreaElement || + element?.getAttribute("contenteditable") === "true"; + + const handleModuleSwitch = (keyCombination: string) => { + const modules: Record = { + "1": "builder", + "2": "simulation", + "3": "visualization", + "4": "market", + }; + const module = modules[keyCombination]; + if (module && !toggleView) { + setActiveTool("cursor"); + setActiveSubTool("cursor"); + if (module === "market") setToggleUI(false); + setActiveModule(module); + } + }; + + const handlePrimaryTools = (key: string) => { + const toolMap: Record = { + V: "cursor", + X: "delete", + H: "free-hand", + }; + const tool = toolMap[key]; + if (tool) { + setActiveTool(tool); + setActiveSubTool(tool); + } + }; + + const handleBuilderShortcuts = (key: string) => { + if (activeModule !== "builder") return; + + if (key === "TAB") { + const toggleTo2D = toggleView; + setToggleView(!toggleTo2D); + setToggleThreeD(toggleTo2D); + if (toggleTo2D) { + setSelectedWallItem(null); + setDeleteTool(false); + setAddAction(null); + } + setActiveTool("cursor"); + setActiveSubTool("cursor"); + return; + } + + // These should only apply in 2D view + const twoDToolConfigs: Record = { + Q: { tool: "draw-wall", mode: "Wall" }, + "6": { tool: "draw-wall", mode: "Wall" }, + R: { tool: "draw-aisle", mode: "Aisle" }, + "7": { tool: "draw-aisle", mode: "Aisle" }, + E: { tool: "draw-zone", mode: "Zone" }, + "8": { tool: "draw-zone", mode: "Zone" }, + T: { tool: "draw-floor", mode: "Floor" }, + "9": { tool: "draw-floor", mode: "Floor" }, + }; + + const config = twoDToolConfigs[key]; + if (toggleView && config) { + setActiveTool(config.tool); + setToolMode(config.mode); + } + + // Measurement tool should work in both 2D and 3D + if (key === "M") { + setActiveTool("measure"); + setToolMode("MeasurementScale"); + } + }; + + + const handleKeyPress = (event: KeyboardEvent) => { + if (isTextInput(document.activeElement)) return; + + const keyCombination = detectModifierKeys(event); + if (!keyCombination || ["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R") return; + + event.preventDefault(); + + if (keyCombination === "Ctrl+\\") { + if (activeModule !== "market") setToggleUI(!toggleUI); + return; + } + + // Active module selection (builder, simulation, etc.) + handleModuleSwitch(keyCombination); + // Common editing tools: cursor | delete | free-hand + handlePrimaryTools(keyCombination); + // Shortcuts specific to the builder module (e.g., drawing and measurement tools) + handleBuilderShortcuts(keyCombination); + + // Shortcut to enter play mode + if (keyCombination === "Ctrl+P" && !toggleView) { + setIsPlaying(true); + } + + if (keyCombination === "ESCAPE") { + setActiveTool("cursor"); + setIsPlaying(false); + } + + // Placeholder for future implementation + if (["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+H", "Ctrl+F", "Ctrl+?"].includes(keyCombination)) { + // Implement undo/redo/help/find/shortcuts + } + }; - // useEffect to manage global keyboard shortcuts useEffect(() => { - // Function to handle keydown events - const handleKeyPress = (event: KeyboardEvent) => { - // Identify the currently focused element - const activeElement = document.activeElement; - - // Check if the user is typing in an input field, textarea, or contenteditable element - const isTyping = - activeElement instanceof HTMLInputElement || - activeElement instanceof HTMLTextAreaElement || - (activeElement && activeElement.getAttribute("contenteditable") === "true"); - - if (isTyping) { - return; // Skip shortcut handling while typing - } - - // Detect the combination of keys pressed - const keyCombination = detectModifierKeys(event); - - // Allow browser default behavior for specific keys (e.g., F5 for refresh) - if (["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R") { - return; - } - - // Prevent the default browser action for other handled key presses - event.preventDefault(); - - if (keyCombination) { - // Switch between different modules (e.g., builder, simulation) - if (keyCombination === "1" && !toggleView) { - setActiveTool("cursor"); - setActiveSubTool("cursor"); - setActiveModule("builder"); - } - if (keyCombination === "2" && !toggleView) { - setActiveTool("cursor"); - setActiveSubTool("cursor"); - setActiveModule("simulation"); - } - if (keyCombination === "3" && !toggleView) { - setActiveTool("cursor"); - setActiveSubTool("cursor"); - setActiveModule("visualization"); - } - if (keyCombination === "4" && !toggleView) { - setActiveTool("cursor"); - setActiveSubTool("cursor"); - setToggleUI(false); - setActiveModule("market"); - } - - // Toggle UI visibility - if (keyCombination === "Ctrl+." && activeModule !== "market") { - setToggleUI(!toggleUI); - } - - // Tool selection shortcuts - if (keyCombination === "V") { - setActiveTool("cursor"); - setActiveSubTool("cursor"); - } - if (keyCombination === "X") { - setActiveTool("delete"); - setActiveSubTool("delete"); - } - if (keyCombination === "H") { - setActiveTool("free-hand"); - setActiveSubTool("free-hand"); - } - - // Toggle play mode - if (keyCombination === "Ctrl+P" && !toggleView) { - setIsPlaying(true); - } - - // Builder-specific shortcuts - if (activeModule === "builder") { - if (keyCombination === "TAB") { - // Switch between 2D and 3D views - if (toggleView) { - setToggleView(false); - setToggleThreeD(true); - setActiveTool("cursor"); - } else { - setSelectedWallItem(null); - setDeleteTool(false); - setAddAction(null); - setToggleView(true); - setToggleThreeD(false); - setActiveTool("cursor"); - } - } - - // Wall-related tools - if (toggleView) { - if (keyCombination === "Q" || keyCombination === "6") { - setActiveTool("draw-wall"); - setToolMode("Wall"); - } - if (keyCombination === "R" || keyCombination === "7") { - setActiveTool("draw-aisle"); - setToolMode("Aisle"); - } - if (keyCombination === "E" || keyCombination === "8") { - setActiveTool("draw-zone"); - setToolMode("Zone"); - } - if (keyCombination === "T" || keyCombination === "9") { - setActiveTool("draw-floor"); - setToolMode("Floor"); - } - } - - // Measurement tool - if (keyCombination === "M") { - setActiveTool("measure"); - setToolMode("MeasurementScale"); - } - } - - // Undo and redo actions - if (keyCombination === "Ctrl+Z") { - // Handle undo action - } - if (keyCombination === "Ctrl+Y" || keyCombination === "Ctrl+Shift+Z") { - // Handle redo action - } - - // Helper actions - if (keyCombination === "Ctrl+H") { - // Open help - } - if (keyCombination === "Ctrl+F") { - // Open find functionality - } - if (keyCombination === "Ctrl+?") { - // Show shortcuts info - } - - // Reset to cursor tool and stop play mode - if (keyCombination === "ESCAPE") { - setActiveTool("cursor"); - setIsPlaying(false); - } - } - }; - - // Add keydown event listener window.addEventListener("keydown", handleKeyPress); + return () => window.removeEventListener("keydown", handleKeyPress); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [activeModule, toggleUI, toggleView]); - // Cleanup function to remove the event listener - return () => { - window.removeEventListener("keydown", handleKeyPress); - }; - }, [activeModule, setActiveModule, setActiveSubTool, setActiveTool, setAddAction, setDeleteTool, setIsPlaying, setSelectedWallItem, setToggleThreeD, setToggleUI, setToggleView, setToolMode, toggleUI, toggleView]); // Dependencies to reapply effect if these values change - - return null; // This component does not render any UI + return null; }; export default KeyPressListener;