From 4337bb9056d42e1a3672d11dc7a0061094101d02 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 13 May 2025 10:32:24 +0530 Subject: [PATCH] Refactor sidebar toggle functionality to support independent left and right UI states; update related components and styles for improved usability --- .../components/layout/sidebarLeft/Header.tsx | 12 +- .../layout/sidebarLeft/SideBarLeft.tsx | 88 +++++++------- .../components/layout/sidebarRight/Header.tsx | 24 ++++ .../layout/sidebarRight/SideBarRight.tsx | 16 +-- app/src/components/ui/ModuleToggle.tsx | 23 ++-- app/src/components/ui/Tools.tsx | 78 +++++++----- app/src/store/useUIToggleStore.ts | 12 +- app/src/styles/layout/sidebar.scss | 113 ++++++++++-------- app/src/styles/layout/skeleton.scss | 102 +++++++++------- .../utils/shortcutkeys/handleShortcutKeys.ts | 29 ++++- 10 files changed, 300 insertions(+), 197 deletions(-) diff --git a/app/src/components/layout/sidebarLeft/Header.tsx b/app/src/components/layout/sidebarLeft/Header.tsx index 70668af..f26f4fa 100644 --- a/app/src/components/layout/sidebarLeft/Header.tsx +++ b/app/src/components/layout/sidebarLeft/Header.tsx @@ -6,7 +6,7 @@ import useToggleStore from "../../../store/useUIToggleStore"; import useModuleStore from "../../../store/useModuleStore"; const Header: React.FC = () => { - const { toggleUI, setToggleUI } = useToggleStore(); + const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore(); const { activeModule } = useModuleStore(); return ( @@ -20,15 +20,17 @@ const Header: React.FC = () => { diff --git a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx index 0765b95..eb618ec 100644 --- a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx +++ b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx @@ -12,7 +12,7 @@ import Search from "../../ui/inputs/Search"; const SideBarLeft: React.FC = () => { const [activeOption, setActiveOption] = useState("Widgets"); - const { toggleUI } = useToggleStore(); + const { toggleUILeft } = useToggleStore(); const { activeModule } = useModuleStore(); // Reset activeOption whenever activeModule changes @@ -31,47 +31,55 @@ const SideBarLeft: React.FC = () => { }; return ( -
+
- {toggleUI && ( + {toggleUILeft && (
- {activeModule === "visualization" ? ( - <> - - -
- {activeOption === "Widgets" ? : } -
- - ) : activeModule === "market" ? ( - <> - ) : activeModule === "builder" ? ( - <> - -
- {activeOption === "Outline" ? : } -
- - ) : ( - <> - -
- {activeOption === "Outline" ? : } -
- - )} + {(() => { + if (activeModule === "visualization") { + return ( + <> + + +
+ {activeOption === "Widgets" ? : } +
+ + ); + } else if (activeModule === "market") { + return <>; + } else if (activeModule === "builder") { + return ( + <> + +
+ {activeOption === "Outline" ? : } +
+ + ); + } else { + return ( + <> + +
+ {activeOption === "Outline" ? : } +
+ + ); + } + })()}
)}
diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx index 3684157..c7c3070 100644 --- a/app/src/components/layout/sidebarRight/Header.tsx +++ b/app/src/components/layout/sidebarRight/Header.tsx @@ -5,10 +5,15 @@ import { ActiveUser } from "../../../types/users"; import CollaborationPopup from "../../templates/CollaborationPopup"; import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; import { useSelectedUserStore } from "../../../store/useCollabStore"; +import useToggleStore from "../../../store/useUIToggleStore"; +import { ToggleSidebarIcon } from "../../icons/HeaderIcons"; +import useModuleStore from "../../../store/useModuleStore"; const Header: React.FC = () => { const { activeUsers } = useActiveUsers(); const userName = localStorage.getItem("userName") ?? "Anonymous"; + const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore(); + const { activeModule } = useModuleStore(); const guestUsers: ActiveUser[] = activeUsers.filter( (user: ActiveUser) => user.userName !== userName @@ -55,6 +60,25 @@ const Header: React.FC = () => { )}
+
)} {/* process builder */} - {toggleUI && + {toggleUIRight && subModule === "properties" && activeModule !== "visualization" && !selectedFloorItem && ( @@ -114,7 +114,7 @@ const SideBarRight: React.FC = () => {
)} - {toggleUI && + {toggleUIRight && subModule === "properties" && activeModule !== "visualization" && selectedFloorItem && ( @@ -124,7 +124,7 @@ const SideBarRight: React.FC = () => { )} - {toggleUI && + {toggleUIRight && subModule === "zoneProperties" && (activeModule === "builder" || activeModule === "simulation") && (
@@ -134,7 +134,7 @@ const SideBarRight: React.FC = () => {
)} {/* simulation */} - {toggleUI && activeModule === "simulation" && ( + {toggleUIRight && activeModule === "simulation" && ( <> {subModule === "simulations" && (
@@ -160,7 +160,7 @@ const SideBarRight: React.FC = () => { )} {/* realtime visualization */} - {toggleUI && activeModule === "visualization" && } + {toggleUIRight && activeModule === "visualization" && }
); }; diff --git a/app/src/components/ui/ModuleToggle.tsx b/app/src/components/ui/ModuleToggle.tsx index a1583e1..4a1532f 100644 --- a/app/src/components/ui/ModuleToggle.tsx +++ b/app/src/components/ui/ModuleToggle.tsx @@ -19,8 +19,11 @@ const ModuleToggle: React.FC = () => { onClick={() => { setActiveModule("builder"); setToggleUI( - localStorage.getItem("navBarUi") - ? localStorage.getItem("navBarUi") === "true" + localStorage.getItem("navBarUiLeft") + ? localStorage.getItem("navBarUiLeft") === "true" + : true, + localStorage.getItem("navBarUiRight") + ? localStorage.getItem("navBarUiRight") === "true" : true ); }} @@ -37,8 +40,11 @@ const ModuleToggle: React.FC = () => { onClick={() => { setActiveModule("simulation"); setToggleUI( - localStorage.getItem("navBarUi") - ? localStorage.getItem("navBarUi") === "true" + localStorage.getItem("navBarUiLeft") + ? localStorage.getItem("navBarUiLeft") === "true" + : true, + localStorage.getItem("navBarUiRight") + ? localStorage.getItem("navBarUiRight") === "true" : true ); }} @@ -55,8 +61,11 @@ const ModuleToggle: React.FC = () => { onClick={() => { setActiveModule("visualization"); setToggleUI( - localStorage.getItem("navBarUi") - ? localStorage.getItem("navBarUi") === "true" + localStorage.getItem("navBarUiLeft") + ? localStorage.getItem("navBarUiLeft") === "true" + : true, + localStorage.getItem("navBarUiRight") + ? localStorage.getItem("navBarUiRight") === "true" : true ); }} @@ -70,7 +79,7 @@ const ModuleToggle: React.FC = () => { className={`module-list ${activeModule === "market" ? "active" : ""}`} onClick={() => { setActiveModule("market"); - setToggleUI(false); + setToggleUI(false, false); }} >
diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 2187fdc..c90edcf 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -70,8 +70,11 @@ const Tools: React.FC = () => { // Reset activeTool whenever activeModule changes useEffect(() => { setToggleUI( - localStorage.getItem("navBarUi") - ? localStorage.getItem("navBarUi") === "true" + localStorage.getItem("navBarUiLeft") + ? localStorage.getItem("navBarUiLeft") === "true" + : true, + localStorage.getItem("navBarUiRight") + ? localStorage.getItem("navBarUiRight") === "true" : true ); }, []); @@ -92,8 +95,11 @@ const Tools: React.FC = () => { setToggleView(false); } setToggleUI( - localStorage.getItem("navBarUi") - ? localStorage.getItem("navBarUi") === "true" + localStorage.getItem("navBarUiLeft") + ? localStorage.getItem("navBarUiLeft") === "true" + : true, + localStorage.getItem("navBarUiRight") + ? localStorage.getItem("navBarUiRight") === "true" : true ); setToggleThreeD(!toggleThreeD); @@ -118,7 +124,7 @@ const Tools: React.FC = () => { }, []); useEffect(() => { if (!toggleThreeD) { - setToggleUI(false); + setToggleUI(false, false); } }, [toggleThreeD]); @@ -133,7 +139,7 @@ const Tools: React.FC = () => { switch (activeTool) { case "cursor": if (toggleView) { - setToolMode('move'); + setToolMode("move"); } else { setTransformMode("translate"); } @@ -208,8 +214,9 @@ const Tools: React.FC = () => {
{activeSubTool == "cursor" && (
{ setActiveTool("cursor"); }} @@ -220,8 +227,9 @@ const Tools: React.FC = () => { )} {activeSubTool == "free-hand" && (
{ setActiveTool("free-hand"); }} @@ -232,8 +240,9 @@ const Tools: React.FC = () => { )} {activeSubTool == "delete" && (
{ setActiveTool("delete"); }} @@ -306,8 +315,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-wall"); }} @@ -316,8 +326,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-zone"); }} @@ -326,8 +337,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-aisle"); }} @@ -336,8 +348,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-floor"); }} @@ -353,8 +366,9 @@ const Tools: React.FC = () => {
{ setActiveTool("measure"); }} @@ -370,8 +384,9 @@ const Tools: React.FC = () => {
{ setActiveTool("pen"); }} @@ -408,8 +423,9 @@ const Tools: React.FC = () => {
{ setActiveTool("comment"); }} @@ -419,8 +435,9 @@ const Tools: React.FC = () => {
{toggleThreeD && (
{ setIsPlaying(!isPlaying); }} @@ -434,8 +451,9 @@ const Tools: React.FC = () => { <>
toggle view (tab)
diff --git a/app/src/store/useUIToggleStore.ts b/app/src/store/useUIToggleStore.ts index a508b38..9f5f583 100644 --- a/app/src/store/useUIToggleStore.ts +++ b/app/src/store/useUIToggleStore.ts @@ -1,13 +1,17 @@ import { create } from "zustand"; interface ToggleState { - toggleUI: boolean; // State to track UI toggle - setToggleUI: (value: boolean) => void; // Action to update toggleUI + toggleUILeft: boolean; + toggleUIRight: boolean; + setToggleUI: (value1: boolean, value2: boolean) => void; } const useToggleStore = create((set) => ({ - toggleUI: true, // Initial state - setToggleUI: (value: boolean) => set({ toggleUI: value }), // Update the state + toggleUILeft: true, + toggleUIRight: false, + setToggleUI: (value1: boolean, value2: boolean) => { + set({ toggleUILeft: value1, toggleUIRight: value2 }); + }, })); export default useToggleStore; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 0b7743f..317868f 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -1,6 +1,55 @@ @use "../abstracts/variables" as *; @use "../abstracts/mixins" as *; +.toggle-sidebar-ui-button { + @include flex-center; + cursor: pointer; + height: 32px; + width: 32px; + min-height: 32px; + min-width: 32px; + border-radius: #{$border-radius-large}; + position: relative; + + .tooltip { + top: 6px; + right: -168px; + + &::after { + left: 0px; + bottom: 50%; + } + } + + &:hover { + outline: 1px solid var(--border-color); + outline-offset: -1px; + background: var(--background-color-solid); + + .tooltip { + opacity: 1; + transform: translateX(2px); + } + } +} + +.toggle-sidebar-ui-button.active { + background: var(--background-color-accent); + + rect { + stroke: var(--icon-default-color-active); + } + + circle { + fill: var(--icon-default-color-active); + } + + &:hover { + filter: saturate(0.8); + background: var(--background-color-accent); + } +} + .sidebar-left-wrapper { width: 270px; position: fixed; @@ -34,15 +83,6 @@ } .toggle-sidebar-ui-button { - @include flex-center; - cursor: pointer; - height: 32px; - width: 32px; - min-height: 32px; - min-width: 32px; - border-radius: #{$border-radius-large}; - position: relative; - .tooltip { top: 6px; right: -168px; @@ -52,34 +92,6 @@ bottom: 50%; } } - - &:hover { - outline: 1px solid var(--border-color); - outline-offset: -1px; - background: var(--background-color-solid); - - .tooltip { - opacity: 1; - transform: translateX(2px); - } - } - } - - .active { - background: var(--background-color-accent); - - rect { - stroke: var(--icon-default-color-active); - } - - circle { - fill: var(--icon-default-color-active); - } - - &:hover { - filter: saturate(0.8); - background: var(--background-color-accent); - } } } @@ -295,7 +307,7 @@ padding: 10px; padding-left: 16px; width: 100%; - gap: 12px; + gap: 8px; height: 52px; .options-container { @@ -318,7 +330,7 @@ .split { height: 20px; - width: 2px; + min-width: 1px; background: var(--text-disabled); } @@ -1265,6 +1277,15 @@ } } } + .toggle-sidebar-ui-button { + .tooltip { + right: 56px; + &::after { + left: 100%; + bottom: 50%; + } + } + } } .assets-container-main { @@ -1490,20 +1511,6 @@ } } -.skeleton-wrapper { - display: flex; - - .asset-name { - width: 40%; - height: 10px; - } - - .asset { - width: 100%; - height: 100%; - } -} - .sidebar-left-wrapper, .sidebar-right-wrapper { transition: height 0.2s ease-in-out; diff --git a/app/src/styles/layout/skeleton.scss b/app/src/styles/layout/skeleton.scss index 9df0331..2b3e759 100644 --- a/app/src/styles/layout/skeleton.scss +++ b/app/src/styles/layout/skeleton.scss @@ -1,61 +1,73 @@ .skeleton-wrapper { // max-width: 600px; + display: flex; margin: 0 auto; width: 100%; + + .asset-name { + width: 40%; + height: 10px; + } + + .asset { + width: 100%; + height: 100%; + } + .skeleton { + background: var(--background-color-gray); - .skeleton { - background: var(--background-color-gray); + border-radius: 8px; + position: relative; + overflow: hidden; - border-radius: 8px; - position: relative; - overflow: hidden; + &::after { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-image: linear-gradient( + 90deg, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.2) 20%, + rgba(255, 255, 255, 0.5) 60%, + rgba(255, 255, 255, 0) 100% + ); + transform: translateX(-100%); + animation: shimmer 1.5s infinite; + } + } - &::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-image: linear-gradient(90deg, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0.2) 20%, - rgba(255, 255, 255, 0.5) 60%, - rgba(255, 255, 255, 0) 100%); - transform: translateX(-100%); - animation: shimmer 1.5s infinite; - } + .skeleton-header { + margin-bottom: 20px; + + .skeleton-title { + width: 100%; + height: 25px; + margin-bottom: 12px; } - .skeleton-header { - margin-bottom: 20px; - - .skeleton-title { - width: 100%; - height: 25px; - margin-bottom: 12px; - } - - .skeleton-subtitle { - width: 100%; - height: 4px; - } + .skeleton-subtitle { + width: 100%; + height: 4px; } + } - .skeleton-content { - display: flex; - flex-direction: column; - gap: 16px; + .skeleton-content { + display: flex; + flex-direction: column; + gap: 16px; - .skeleton-card { - width: 100%; - height: 15px; - } + .skeleton-card { + width: 100%; + height: 15px; } + } } @keyframes shimmer { - 100% { - transform: translateX(100%); - } -} \ No newline at end of file + 100% { + transform: translateX(100%); + } +} diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 2ff5f39..bb87970 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -17,7 +17,7 @@ import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; const KeyPressListener: React.FC = () => { const { activeModule, setActiveModule } = useModuleStore(); const { setActiveSubTool } = useActiveSubTool(); - const { toggleUI, setToggleUI } = useToggleStore(); + const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore(); const { setToggleThreeD } = useThreeDStore(); const { setToolMode } = useToolMode(); const { setIsPlaying } = usePlayButtonStore(); @@ -26,7 +26,7 @@ const KeyPressListener: React.FC = () => { const { setAddAction } = useAddAction(); const { setSelectedWallItem } = useSelectedWallItem(); const { setActiveTool } = useActiveTool(); - const { clearSelectedZone} = useSelectedZoneStore(); + const { clearSelectedZone } = useSelectedZoneStore(); const isTextInput = (element: Element | null): boolean => element instanceof HTMLInputElement || @@ -44,7 +44,7 @@ const KeyPressListener: React.FC = () => { if (module && !toggleView) { setActiveTool("cursor"); setActiveSubTool("cursor"); - if (module === "market") setToggleUI(false); + if (module === "market") setToggleUI(false, false); setActiveModule(module); } }; @@ -69,6 +69,7 @@ const KeyPressListener: React.FC = () => { const toggleTo2D = toggleView; setToggleView(!toggleTo2D); setToggleThreeD(toggleTo2D); + setToggleUI(toggleTo2D, toggleTo2D); if (toggleTo2D) { setSelectedWallItem(null); setDeleteTool(false); @@ -114,7 +115,24 @@ const KeyPressListener: React.FC = () => { event.preventDefault(); if (keyCombination === "Ctrl+\\") { - if (activeModule !== "market") setToggleUI(!toggleUI); + if (toggleUILeft === toggleUIRight) { + setToggleUI(!toggleUILeft, !toggleUIRight); + } + else { + activeModule !== "market" && setToggleUI(true, true); + } + return; + } + if (keyCombination === "Ctrl+]") { + if (activeModule !== "market") { + setToggleUI(toggleUILeft, !toggleUIRight); + } + return; + } + if (keyCombination === "Ctrl+[") { + if (activeModule !== "market") { + setToggleUI(!toggleUILeft, toggleUIRight); + } return; } @@ -132,6 +150,7 @@ const KeyPressListener: React.FC = () => { if (keyCombination === "ESCAPE") { setActiveTool("cursor"); + setActiveSubTool("cursor"); setIsPlaying(false); clearSelectedZone(); } @@ -146,7 +165,7 @@ const KeyPressListener: React.FC = () => { window.addEventListener("keydown", handleKeyPress); return () => window.removeEventListener("keydown", handleKeyPress); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeModule, toggleUI, toggleView]); + }, [activeModule, toggleUIRight, toggleUILeft, toggleView]); return null; };