Refactor Tools and Menu components for improved state management and UI responsiveness

This commit is contained in:
2025-05-13 17:21:17 +05:30
parent fefe4d8456
commit aa300ac576
3 changed files with 181 additions and 507 deletions

View File

@@ -160,15 +160,21 @@ const Tools: React.FC = () => {
}; };
const toggle2D3D = () => { const toggle2D3D = () => {
setToggleThreeD(!toggleThreeD); const toggleTo2D = toggleView;
setToggleView(!toggleTo2D);
setToggleThreeD(toggleTo2D);
setToggleUI(toggleTo2D, toggleTo2D);
if (toggleTo2D) {
setSelectedWallItem(null);
setDeleteTool(false);
setAddAction(null);
}
setActiveTool("cursor");
setActiveSubTool("cursor");
setToggleUI( setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false", localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false" localStorage.getItem("navBarUiRight") !== "false"
); );
setSelectedWallItem(null);
setActiveSubTool("cursor");
setActiveTool("cursor");
setToggleView(!toggleThreeD);
}; };
if (isPlaying && activeModule !== "simulation") { if (isPlaying && activeModule !== "simulation") {

View File

@@ -1,385 +1,198 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { ArrowIcon } from "../../icons/ExportCommonIcons"; import { ArrowIcon } from "../../icons/ExportCommonIcons";
import { toggleTheme } from "../../../utils/theme"; import { toggleTheme } from "../../../utils/theme";
import { useNavigate } from "react-router-dom"; import useVersionHistoryStore, { useShortcutStore } from "../../../store/store";
import useVersionHistoryStore from "../../../store/store";
import { useSubModuleStore } from "../../../store/useModuleStore"; import { useSubModuleStore } from "../../../store/useModuleStore";
interface MenuBarProps { interface MenuBarProps {
setOpenMenu: (isOpen: boolean) => void; // Function to update menu state setOpenMenu: (isOpen: boolean) => void;
}
interface MenuItem {
label: string;
onClick?: string;
shortcut?: string;
submenu?: MenuItem[];
action?: () => void;
} }
const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => { const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const [activeMenu, setActiveMenu] = useState<string | null>(null); const [activeMenu, setActiveMenu] = useState<string | null>(null);
const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null); const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null);
const { setVersionHistory } = useVersionHistoryStore();
const { setSubModule } = useSubModuleStore();
// State to track selection for all menu items
const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>( const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>(
{} {}
); );
// Function to toggle selection for a specific item const { setVersionHistory } = useVersionHistoryStore();
const { setSubModule } = useSubModuleStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
const savedTheme = localStorage.getItem("theme") ?? "light";
const toggleSelection = (itemName: string) => { const toggleSelection = (itemName: string) => {
setSelectedItems((prev) => ({ setSelectedItems((prev) => ({
...prev, ...prev,
[itemName]: !prev[itemName], // Toggle the selection state [itemName]: !prev[itemName],
})); }));
}; };
function handleThemeChange() { // functions
const handleThemeChange = () => {
toggleTheme(); toggleTheme();
window.location.reload(); window.location.reload();
}
const savedTheme: string | null = localStorage.getItem("theme") ?? "light";
const handleLogout = () => {
localStorage.clear(); // 1. Clear all localStorage
navigate('/'); // 2. Redirect to homepage
}; };
return ( const handleLogout = () => {
<div localStorage.clear();
className="menu-bar" navigate("/");
onPointerLeave={() => { };
setOpenMenu(false);
function handleShotcutsHelper() {
setShowShortcuts(!showShortcuts);
}
const menus: Record<string, MenuItem[]> = {
File: [
{ label: "New File", shortcut: "Ctrl + N" },
{ label: "Open Local File", shortcut: "Ctrl + O" },
{ label: "Save Version" },
{ label: "Make a Copy" },
{ label: "Share" },
{ label: "Rename" },
{ label: "Import" },
{ label: "Close File" },
],
Edit: [
{ label: "Undo", shortcut: "Ctrl + Z" },
{ label: "Redo", shortcut: "Ctrl + Shift + Z" },
{ label: "Undo History" },
{ label: "Redo History" },
{ label: "Find", shortcut: "Ctrl + F" },
{ label: "Delete" },
{ label: "Select by..." },
{ label: "Keymap" },
],
View: [
{ label: "Grid" },
{
label: "Gizmo",
submenu: [
{ label: "Visibility" },
{ label: "Cube view" },
{ label: "Sphere view" },
],
},
{ label: "Zoom" },
{ label: "Full Screen", shortcut: "F11" },
],
Help: [
{
label: "Shortcuts",
shortcut: "Ctrl + Shift + ?",
action: handleShotcutsHelper,
},
{ label: "Manual" },
{ label: "Video Tutorials" },
{ label: "Report a bug" },
],
};
// render menu item and sub menu item component
const renderMenuItem = ({ label, shortcut, action }: MenuItem) => (
<button
className="menu-item-container"
key={label}
onClick={() => {
toggleSelection(label);
action && action();
}} }}
> >
{/* Top-level menu buttons */} <div className="menu-item">
<span>
{selectedItems[label] ? "✓ " : ""}
{label}
</span>
{shortcut && (
<div className="menu-item-right">
<span className="shortcut">{shortcut}</span>
</div>
)}
</div>
</button>
);
const renderSubMenu = (submenu: MenuItem[], parentLabel: string) => (
<div className="submenu">
{submenu.map((item) => (
<button
key={item.label}
className="submenu-item"
onClick={() => {
console.log("hi", item.onClick);
toggleSelection(item.label);
}}
>
<span>
{selectedItems[item.label] ? "✓ " : ""}
{item.label}
</span>
</button>
))}
</div>
);
return (
<div className="menu-bar" onPointerLeave={() => setOpenMenu(false)}>
<div className="menu-buttons"> <div className="menu-buttons">
{/* File Menu */} {Object.entries(menus).map(([menu, items]) => (
<div <button
className="menu-button-container" key={menu}
onMouseEnter={() => setActiveMenu("File")} className="menu-button-container"
onMouseLeave={() => { onMouseEnter={() => setActiveMenu(menu)}
setActiveMenu(null); onMouseLeave={() => {
setActiveSubMenu(null); setActiveMenu(null);
}} setActiveSubMenu(null);
> }}
<div className="menu-button"> >
File <div className="menu-button">
<span className="dropdown-icon"> {menu}
<ArrowIcon /> <span className="dropdown-icon">
</span> <ArrowIcon />
</div> </span>
{/* File Dropdown */}
{activeMenu === "File" && (
<div className="dropdown-menu">
{/* New File */}
<div
className="menu-item-container"
onClick={() => toggleSelection("New File")}
>
<div className="menu-item">
<span>New File</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + N</span>
</div>
</div>
</div>
{/* Open Local File */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Open Local File")}
>
<div className="menu-item">
<span>Open Local File</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + O</span>
</div>
</div>
</div>
{/* Save Version */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Save Version")}
>
<div className="menu-item">
<span>Save Version</span>
</div>
<div className="split"></div>
</div>
{/* Make a Copy */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Make a Copy")}
>
<div className="menu-item">
<span>Make a Copy</span>
</div>
</div>
{/* Share */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Share")}
>
<div className="menu-item">
<span>Share</span>
</div>
</div>
{/* Rename */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Rename")}
>
<div className="menu-item">
<span>Rename</span>
</div>
<div className="split"></div>
</div>
{/* Import */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Import")}
>
<div className="menu-item">
<span>Import</span>
</div>
</div>
{/* Close File */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Close File")}
>
<div className="menu-item">
<span>Close File</span>
</div>
</div>
</div> </div>
)}
</div>
{/* Edit Menu */} {activeMenu === menu && (
<div <div className="dropdown-menu">
className="menu-button-container" {items.map((item) =>
onMouseEnter={() => setActiveMenu("Edit")} item.submenu ? (
onMouseLeave={() => { <button
setActiveMenu(null); key={item.label}
setActiveSubMenu(null); className="menu-item-container"
}} onMouseEnter={() => setActiveSubMenu(item.label)}
> onMouseLeave={() => setActiveSubMenu(null)}
<div className="menu-button">
Edit
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* Edit Dropdown */}
{activeMenu === "Edit" && (
<div className="dropdown-menu">
{/* Undo */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Undo")}
>
<div className="menu-item">
<span>Undo</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + Z</span>
</div>
</div>
</div>
{/* Redo */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Redo")}
>
<div className="menu-item">
<span>Redo</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + Shift + Z</span>
</div>
</div>
<div className="split"></div>
</div>
{/* Undo History */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Undo History")}
>
<div className="menu-item">
<span>Undo History</span>
</div>
</div>
{/* Redo History */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Redo History")}
>
<div className="menu-item">
<span>Redo History</span>
</div>
<div className="split"></div>
</div>
{/* Find */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Find")}
>
<div className="menu-item">
<span>Find</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + F</span>
</div>
</div>
</div>
{/* Delete */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Delete")}
>
<div className="menu-item">
<span>Delete</span>
</div>
</div>
{/* Select by... */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Select by...")}
>
<div className="menu-item">
<span>Select by...</span>
</div>
</div>
{/* Keymap */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Keymap")}
>
<div className="menu-item">
<span>Keymap</span>
</div>
</div>
</div>
)}
</div>
{/* View Menu */}
<div
className="menu-button-container"
onMouseEnter={() => setActiveMenu("View")}
onMouseLeave={() => {
setActiveMenu(null);
setActiveSubMenu(null);
}}
>
<div className="menu-button">
View
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* View Dropdown */}
{activeMenu === "View" && (
<div className="dropdown-menu">
{/* Grid */}
<div
className={"menu-item-container"}
onClick={() => toggleSelection("Grid")}
>
<div className="menu-item">
<span>Grid</span>
</div>
</div>
{/* Gizmo */}
<div
className="menu-item-container"
onMouseEnter={() => setActiveSubMenu("View-Gizmo")}
onMouseLeave={() => setActiveSubMenu(null)}
>
<div className="menu-item">
<span>Gizmo</span>
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
<div className="split"></div>
{/* Gizmo Submenu */}
{activeSubMenu === "View-Gizmo" && (
<div className="submenu">
{/* Visibility */}
<div
className="submenu-item"
onClick={() => toggleSelection("Visibility")}
> >
<span> <div className="menu-item">
{selectedItems["Visibility"] && "✓ "} <span>{item.label}</span>
Visibility <span className="dropdown-icon">
</span> <ArrowIcon />
</div> </span>
<div className="split"></div> </div>
{activeSubMenu === item.label &&
{/* Cube view */} renderSubMenu(item.submenu, item.label)}
<div </button>
className="submenu-item" ) : (
onClick={() => toggleSelection("Cube view")} renderMenuItem(item)
> )
<span>Cube view</span>
</div>
{/* Sphere view */}
<div
className="submenu-item"
onClick={() => toggleSelection("Sphere view")}
>
<span>Sphere view</span>
</div>
</div>
)} )}
</div> </div>
)}
</button>
))}
{/* Zoom */} {/* Version History */}
<div <button
className="menu-item-container"
onClick={() => toggleSelection("Zoom")}
>
<div className="menu-item">
<span>Zoom</span>
</div>
</div>
{/* Full Screen */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Full Screen")}
>
<div className="menu-item">
<span>Full Screen</span>
<div className="menu-item-right">
<span className="shortcut">F11</span>
</div>
</div>
</div>
</div>
)}
</div>
{/* Version History Menu */}
<div
className="menu-button-container" className="menu-button-container"
onMouseEnter={() => setActiveMenu("Version history")} onMouseEnter={() => setActiveMenu("Version history")}
onMouseLeave={() => { onMouseLeave={() => {
@@ -392,173 +205,27 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
}} }}
> >
<div className="menu-button">Version history</div> <div className="menu-button">Version history</div>
</div> </button>
{/* Export As Menu */} {/* Theme */}
<div <button
className="menu-button-container" className="menu-button-container"
onMouseEnter={() => setActiveMenu("Export as...")} onMouseEnter={() => setActiveMenu("Theme")}
onMouseLeave={() => { onMouseLeave={() => {
setActiveMenu(null); setActiveMenu(null);
setActiveSubMenu(null); setActiveSubMenu(null);
}} }}
> onClick={handleThemeChange}
<div className="menu-button">Export as...</div>
</div>
<div
className="menu-button-container"
onMouseEnter={() => setActiveMenu("theme")}
onMouseLeave={() => {
setActiveMenu(null);
setActiveSubMenu(null);
}}
onClick={() => {
handleThemeChange();
}}
> >
<div className="menu-button"> <div className="menu-button">
Theme <div className="value">{savedTheme}</div> Theme <div className="value">{savedTheme}</div>
</div> </div>
</div> </button>
{/* Apps Menu */} {/* Log out */}
{/* <div <button className="menu-button-container" onClick={handleLogout}>
className="menu-button-container"
onMouseEnter={() => setActiveMenu("Apps")}
onMouseLeave={() => {
setActiveMenu(null);
setActiveSubMenu(null);
}}
>
<div className="menu-button">
Apps
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{activeMenu === "Apps" && (
<div className="dropdown-menu">
<div
className="menu-item-container"
onClick={() => toggleSelection("New App")}
>
<div className="menu-item">
<span>
New App
</span>
</div>
<div className="split"></div>
</div>
<div
className="menu-item-container"
onClick={() => toggleSelection("Work-flow Monitor")}
>
<div className="menu-item">
<span>
Work-flow Monitor
</span>
</div>
</div>
<div
className="menu-item-container"
onClick={() => toggleSelection("Temperature Visualizer")}
>
<div className="menu-item">
<span>
Temperature Visualizer
</span>
</div>
</div>
<div
className="menu-item-container"
onClick={() => toggleSelection("View all")}
>
<div className="menu-item">
<span>
View all
</span>
</div>
</div>
</div>
)}
</div> */}
{/* Help Menu */}
<div
className="menu-button-container"
onMouseEnter={() => setActiveMenu("Help")}
onMouseLeave={() => {
setActiveMenu(null);
setActiveSubMenu(null);
}}
>
<div className="menu-button">
Help
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* Help Dropdown */}
{activeMenu === "Help" && (
<div className="dropdown-menu">
{/* Shortcuts */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Shortcuts")}
>
<div className="menu-item">
<span>Shortcuts</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + Shift + ?</span>
</div>
</div>
</div>
{/* Manual */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Manual")}
>
<div className="menu-item">
<span>Manual</span>
</div>
</div>
{/* Video Tutorials */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Video Tutorials")}
>
<div className="menu-item">
<span>Video Tutorials</span>
</div>
</div>
{/* Report a bug */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Report a bug")}
>
<div className="menu-item">
<span>Report a bug</span>
</div>
</div>
</div>
)}
</div>
<div className="menu-button-container" onClick={handleLogout}>
<div className="menu-button">Log out</div> <div className="menu-button">Log out</div>
</div> </button>
</div> </div>
</div> </div>
); );

View File

@@ -102,6 +102,7 @@
padding: 4px; padding: 4px;
.menu-item-container { .menu-item-container {
position: relative; position: relative;
width: 100%;
.menu-item { .menu-item {
padding: 4px 8px 4px 12px; padding: 4px 8px 4px 12px;
border-radius: #{$border-radius-medium}; border-radius: #{$border-radius-medium};