From 9f61ab2216378cace7b1120e9f971979e0932ba6 Mon Sep 17 00:00:00 2001 From: "Daniel S. Hansen" Date: Tue, 15 Jul 2025 13:51:56 -0700 Subject: [PATCH 1/2] Add side bar transition animation between open and closed --- client/src/components/SettingsButton.jsx | 6 +- client/src/components/sidebar.jsx | 393 ++++++++++++++++++----- 2 files changed, 319 insertions(+), 80 deletions(-) diff --git a/client/src/components/SettingsButton.jsx b/client/src/components/SettingsButton.jsx index 332c84f..afb7936 100644 --- a/client/src/components/SettingsButton.jsx +++ b/client/src/components/SettingsButton.jsx @@ -2,7 +2,7 @@ // for 'Add Widget', 'Edit Widgets', and 'Remove Widgets'. This component will // control settings related to the Widgets on the main canvas. -import { Button, Menu, Portal } from "@chakra-ui/react"; +import { Button, IconButton, Menu, Portal } from "@chakra-ui/react"; import { FiSettings } from "react-icons/fi"; export function SettingsButton(props) { @@ -25,9 +25,9 @@ export function SettingsButton(props) { // This uses Chakra's built in menu component - + diff --git a/client/src/components/sidebar.jsx b/client/src/components/sidebar.jsx index 2f40b1f..39ea197 100644 --- a/client/src/components/sidebar.jsx +++ b/client/src/components/sidebar.jsx @@ -1,4 +1,4 @@ -import { Box, Button, createIcon, CloseButton, IconButton, Stack } from "@chakra-ui/react"; +import { Box, Button, createIcon, CloseButton, IconButton, Stack, useDisclosure, Tooltip } from "@chakra-ui/react"; import { FaVolcano } from "react-icons/fa6"; import { RxHamburgerMenu } from "react-icons/rx"; import { useState } from "react"; @@ -56,87 +56,326 @@ export const Users = createIcon({ ), }); -export default function Sidebar () { + +export default function Sidebar() { const [isOpen, setIsOpen] = useState(true); - const [activeButton, setActiveButton] = useState("Dashboard") + const [activeButton, setActiveButton] = useState("Dashboard"); return ( - <> - {isOpen && ( - - {/* setIsOpen(!isOpen)}> */} - {/* setIsOpen(!isOpen)}> */} - - - - - - - - )} + + setIsOpen(!isOpen)} + // icon={} + > + + + {/* Dashboard */} + - {!isOpen && ( - - setIsOpen(!isOpen)}> - - - setActiveButton("Dashboard")} bg={activeButton === "Dashboard" ? "#A4B6B6" : "transparent"}> - - - setActiveButton("Global")} bg={activeButton === "Global" ? "#A4B6B6" : "transparent"}> + {/* Global Map */} + + + {/* Regional Map */} + + + {/* Volcano */} + + + {/* Admin */} + + ); } + +// THIS CODE WORKS, SAVE IN CASE OF EMERGENCY +// Needed to refactor in order allow transitions to work properly + +// export default function Sidebar () { +// const [isOpen, setIsOpen] = useState(true); +// const [activeButton, setActiveButton] = useState("Dashboard") + +// return ( +// <> +// {isOpen && ( +// +// {/* setIsOpen(!isOpen)}> */} +// {/* setIsOpen(!isOpen)}> */} +// +// +// +// +// +// +// +// )} + +// {!isOpen && ( +// +// setIsOpen(!isOpen)}> +// +// +// setActiveButton("Dashboard")} bg={activeButton === "Dashboard" ? "#A4B6B6" : "transparent"}> +// +// +// setActiveButton("Global")} bg={activeButton === "Global" ? "#A4B6B6" : "transparent"}> +// +// +// setActiveButton("Regional")} bg={activeButton === "Regional" ? "#A4B6B6" : "transparent"}> +// +// +// setActiveButton("Volcano")} bg={activeButton === "Volcano" ? "#A4B6B6" : "transparent"}> +// +// +// setActiveButton("Admin")} bg={activeButton === "Admin" ? "#A4B6B6" : "transparent"}> +// +// +// +// )} + +// +// ); +// } From dc1f4fcdafcb47f35c8ec63b8406374f9a73b089 Mon Sep 17 00:00:00 2001 From: "Daniel S. Hansen" Date: Tue, 15 Jul 2025 15:55:20 -0700 Subject: [PATCH 2/2] Save point, working on sidebar icon positioning during transition --- client/src/components/sidebar.jsx | 107 ++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/client/src/components/sidebar.jsx b/client/src/components/sidebar.jsx index 39ea197..a1a9f25 100644 --- a/client/src/components/sidebar.jsx +++ b/client/src/components/sidebar.jsx @@ -57,13 +57,27 @@ export const Users = createIcon({ }); + + export default function Sidebar() { const [isOpen, setIsOpen] = useState(true); + const [hasFinishedClosing, setHasFinishedClosing] = useState(true); const [activeButton, setActiveButton] = useState("Dashboard"); + const toggleSidebar = () => { + if (isOpen) { + setHasFinishedClosing(false); + setTimeout(() => setIsOpen(false), 10); // Kick off transition + setTimeout(() => setHasFinishedClosing(true), 400) // Match sidebar transition duration + } else { + setIsOpen(true); + setHasFinishedClosing(true); + } + }; + return ( setIsOpen(!isOpen)} + // onClick={() => setIsOpen(!isOpen)} + onClick={toggleSidebar} // icon={} > @@ -90,9 +105,10 @@ export default function Sidebar() { color="#19332D" fontSize="lg" variant="ghost" - justifyContent={isOpen ? "flex-start" : "center"} + justifyContent={isOpen || !hasFinishedClosing ? "flex-start" : "center"} w="100%" onClick={() => setActiveButton("Dashboard")} + // onClick={toggleSidebar} bg={activeButton === "Dashboard" ? "#A4B6B6" : "transparent"} _hover={{ bg: activeButton === "Dashboard" ? "#A4B6B6" : "#EDF1F1", @@ -101,13 +117,15 @@ export default function Sidebar() { {isOpen ? ( <> {/* */} + + {/* Make text appear gradually instead of popping in */} Dashboard @@ -131,8 +150,11 @@ export default function Sidebar() { color="#19332D" fontSize="lg" variant="ghost" - justifyContent={isOpen ? "flex-start" : "center"} + // justifyContent={isOpen || !hasFinishedClosing ? "flex-start" : "center"} + justifyContent="flex-start" w="100%" + h="48px" + px={0} onClick={() => setActiveButton("Global")} bg={activeButton === "Global" ? "#A4B6B6" : "transparent"} _hover={{ @@ -141,29 +163,53 @@ export default function Sidebar() { > {isOpen ? ( <> - {/* */} - - {/* Make text appear gradually instead of popping in */} - - Global Map - + {/* Fixed-width icon container (works both open & closed) */} + + {/* */} + + + + Global Map + + + ) : ( // - + + + )} @@ -172,7 +218,7 @@ export default function Sidebar() { color="#19332D" fontSize="lg" variant="ghost" - justifyContent={isOpen ? "flex-start" : "center"} + justifyContent={isOpen || !hasFinishedClosing ? "flex-start" : "center"} w="100%" onClick={() => setActiveButton("Regional")} bg={activeButton === "Regional" ? "#A4B6B6" : "transparent"} @@ -189,7 +235,7 @@ export default function Sidebar() { style={{ marginLeft: "8px", opacity: isOpen ? 1 : 0, - maxWidth: isOpen ? "200px" : "0px", // prevent layout from expanding before fade-in + maxWidth: isOpen ? "250px" : "0px", // prevent layout from expanding before fade-in overflow: "hidden", whiteSpace: "nowrap", display: "inline-block", @@ -197,6 +243,7 @@ export default function Sidebar() { transitionDuration: "0.3s", transitionTimingFunction: "ease", transitionDelay: isOpen ? "0.1s" : "0s", + visibility: isOpen || !hasFinishedClosing ? "visible" : "hidden", }} > Regional Map @@ -213,7 +260,7 @@ export default function Sidebar() { color="#19332D" fontSize="lg" variant="ghost" - justifyContent={isOpen ? "flex-start" : "center"} + justifyContent={isOpen || !hasFinishedClosing ? "flex-start" : "center"} w="100%" onClick={() => setActiveButton("Volcano")} bg={activeButton === "Volcano" ? "#A4B6B6" : "transparent"} @@ -229,7 +276,7 @@ export default function Sidebar() { style={{ marginLeft: "8px", opacity: isOpen ? 1 : 0, - maxWidth: isOpen ? "200px" : "0px", // prevent layout from expanding before fade-in + maxWidth: isOpen ? "250px" : "0px", // prevent layout from expanding before fade-in overflow: "hidden", whiteSpace: "nowrap", display: "inline-block", @@ -237,6 +284,7 @@ export default function Sidebar() { transitionDuration: "0.3s", transitionTimingFunction: "ease", transitionDelay: isOpen ? "0.1s" : "0s", + visibility: isOpen || !hasFinishedClosing ? "visible" : "hidden", }} > Volcano @@ -253,7 +301,7 @@ export default function Sidebar() { color="#19332D" fontSize="lg" variant="ghost" - justifyContent={isOpen ? "flex-start" : "center"} + justifyContent={isOpen || !hasFinishedClosing ? "flex-start" : "center"} w="100%" onClick={() => setActiveButton("Admin")} bg={activeButton === "Admin" ? "#A4B6B6" : "transparent"} @@ -278,6 +326,7 @@ export default function Sidebar() { transitionDuration: "0.3s", transitionTimingFunction: "ease", transitionDelay: isOpen ? "0.1s" : "0s", + visibility: isOpen || !hasFinishedClosing ? "visible" : "hidden", }} > Admin