Refactor, cleaned up sidebar and theme

This commit is contained in:
2026-08-26 13:04:17 -07:00
parent 816046d05a
commit c45bc778ec
2 changed files with 98 additions and 93 deletions
+22 -61
View File
@@ -1,22 +1,24 @@
import { useSlotRecipe, Box, Button, IconButton } from "@chakra-ui/react"; import {useSlotRecipe, Box, Button, IconButton} from "@chakra-ui/react";
import { ColorModeButton } from "@/components/ui/color-mode.jsx"; import {ColorModeButton} from "@/components/ui/color-mode.jsx";
import { useState } from "react"; import {useState} from "react";
import { NavLink } from "react-router-dom"; import {NavLink} from "react-router-dom";
import Tooltip from "../ui/Tooltip.jsx"; import Tooltip from "../ui/Tooltip.jsx";
import { Mountain, House, Earth, MapPin, ShieldUser, Menu, PanelLeftClose, PanelLeftOpen } from 'lucide-react'; import {Mountain, House, Earth, MapPin, ShieldUser, Menu, PanelLeftClose, PanelLeftOpen} from 'lucide-react';
const SIDEBAR_DEFAULT_BUTTONS = [ const SIDEBAR_DEFAULT_BUTTONS = [
{ icon: House, name: "Home", url: "/home" }, {icon: House, name: "Home", url: "/home"},
{ icon: Earth, name: "Global Map", url: "/global-map" }, {icon: Earth, name: "Global Map", url: "/global-map"},
{ icon: MapPin, name: "Regional Map", url: "/regional-map" }, {icon: MapPin, name: "Regional Map", url: "/regional-map"},
{ icon: Mountain, name: "Volcano", url: "/volcano" }, {icon: Mountain, name: "Volcano", url: "/volcano"},
{ icon: ShieldUser, name: "Admin", url: "/admin" } // TODO remove in the future as default should not have admin {icon: ShieldUser, name: "Admin", url: "/admin"} // TODO remove in the future as default should not have admin
]; ];
export default function Sidebar() { export default function Sidebar() {
const [isOpen, setIsOpen] = useState(true); const [isOpen, setIsOpen] = useState(true);
const recipe = useSlotRecipe({ key: "sidebar" });
const styles = recipe(); const recipe = useSlotRecipe({key: "sidebar"});
const styles = recipe({state: isOpen ? "open" : "closed"});
// TODO we will need to call buttons here by authorized user, for now we update the visible buttons as simply the default buttons // TODO we will need to call buttons here by authorized user, for now we update the visible buttons as simply the default buttons
const visibleButtons = SIDEBAR_DEFAULT_BUTTONS; const visibleButtons = SIDEBAR_DEFAULT_BUTTONS;
@@ -24,86 +26,45 @@ export default function Sidebar() {
const toggleSidebar = () => setIsOpen((prev) => !prev); const toggleSidebar = () => setIsOpen((prev) => !prev);
return ( return (
<Box <Box css={styles.root}>
css={styles.root}
width={isOpen ? "190px" : "71px"}
transition="width 0.4s ease"
position="relative"
display="flex"
flexDirection="column"
gap={4} // Increased gap slightly to help with the squashed look
pt={4} // Added top padding to give the logo room to breathe
>
{/* Home Link Logo */} {/* Home Link Logo */}
<Button <Button
as={NavLink} as={NavLink}
to="/home" to="/home"
color="color" css={styles.logo}
variant="plain" variant="plain"
fontWeight="bold"
height="auto" // Prevents the large text from squashing vertically
overflow="hidden"
width="100%"
px={0}
justifyContent={isOpen ? "flex-start" : "center"} // Center the 'V' when collapsed
ml={isOpen ? 2 : -1} // Align with other buttons when open
textStyle={isOpen ? "4xl" : "3xl"} // Scale down slightly when closed
> >
{isOpen ? "🌋 VDAP" : "🌋"} {isOpen ? "🌋 VDAP" : "🌋"}
</Button> </Button>
{/* Navigation Buttons */} {/* Navigation Buttons */}
{visibleButtons.map((button) => { {visibleButtons.map((button) => {
const Icon = button.icon; const Icon = button.icon;
return ( return (
// <Tooltip key={button.name} content={button.name} sidebarIsOpen={isOpen}>
<Button <Button
as={NavLink} as={NavLink}
to={button.url} to={button.url}
css={styles.buttons} css={styles.buttons}
justifyContent="flex-start"
width="100%"
// overflow="hidden" // Prevents text popout on collapse
>
<Icon style={{ flexShrink: 0 }} /> {/* Prevents icon from squishing */}
{/* Cleaned conditional transition styling */}
<Box
as="span"
ml={isOpen ? 3 : 0}
opacity={isOpen ? 1 : 0}
visibility={isOpen ? "visible" : "hidden"} // Prevents phantom width calculations and overflow into canvas
transition="opacity 0.3s ease, visibility 0.3s ease, margin 0.3s ease"
whiteSpace="nowrap"
> >
{/* Navigation buttons are [icon text] */}
<Icon/>
<Box as="span" css={styles.button_text}>
{button.name} {button.name}
</Box> </Box>
</Button> </Button>
// </Tooltip>
); );
})} })}
<Box <Box css={styles.footer}>
mt="auto"
display="flex"
flexDirection={isOpen ? "row" : "column-reverse"}
justifyContent="center"
alignItems="center"
gap={isOpen ? 16 : 2}
pb={4}
pr={2}
transition="opacity 0.3s ease, visibility 0.3s ease, margin 0.3s ease"
>
{/* Menu Trigger */} {/* Menu Trigger */}
<IconButton <IconButton
aria-label="Toggle Sidebar" aria-label="Toggle Sidebar"
variant="plain" variant="plain"
size="md" size="md"
onClick={toggleSidebar} onClick={toggleSidebar}
transition="opacity 0.3s ease, visibility 0.3s ease, margin 0.3s ease" css={styles.collapse_button}
> >
{isOpen ? <PanelLeftClose style={{ flexShrink: 0 }} /> : <PanelLeftOpen style={{ flexShrink: 0 }} />} {isOpen ? <PanelLeftClose /> : <PanelLeftOpen />}
</IconButton> </IconButton>
{/* Theme Toggler */} {/* Theme Toggler */}
+47 -3
View File
@@ -29,7 +29,7 @@ const canvasRecipe = defineRecipe({
}); });
const sidebarRecipe = defineSlotRecipe({ const sidebarRecipe = defineSlotRecipe({
slots: ["root", "close_button", "buttons", "dark_mode_button"], slots: ["root", "logo", "footer", "button_text","buttons", "collapse_button"],
base: { base: {
root: { root: {
// 1. Semi-transparent backgrounds // 1. Semi-transparent backgrounds
@@ -57,14 +57,17 @@ const sidebarRecipe = defineSlotRecipe({
margin: "8px", margin: "8px",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
position: "relative",
justifyContent: "start", justifyContent: "start",
alignItems: "stretch", alignItems: "stretch",
gap: 2, gap: 4,
transition: "width 0.4s ease",
// CRITICAL: Adjust padding and overflow to allow the button to touch the right edge // CRITICAL: Adjust padding and overflow to allow the button to touch the right edge
pl: 2, // Keep left padding pl: 2, // Keep left padding
py: 2, // Keep top/bottom padding py: 2, // Keep top/bottom padding
pr: 0, // Remove right padding pr: 0, // Remove right padding
pt: 4, // Added top padding to give the logo room to breathe
overflow: "visible", // Allows the curved corner patches to render outside the button overflow: "visible", // Allows the curved corner patches to render outside the button
zIndex: 10, zIndex: 10,
}, },
@@ -72,10 +75,12 @@ const sidebarRecipe = defineSlotRecipe({
position: "relative", // Required to anchor the corner patches position: "relative", // Required to anchor the corner patches
bg: "transparent", bg: "transparent",
justifyContent: "flex-start",
transition: "background-color 0.4s ease, color 0.4s ease", transition: "background-color 0.4s ease, color 0.4s ease",
"& svg": { "& svg": {
transition: "stroke-width 0.4s ease" transition: "stroke-width 0.4s ease",
flexShrink: "0"
}, },
_hover: { _hover: {
@@ -138,6 +143,45 @@ const sidebarRecipe = defineSlotRecipe({
} }
}, },
}, },
logo: {
width: "100%",
height: "auto",
overflow: "hidden",
fontWeight: "bold",
px: 0,
},
footer: {
mt: "auto",
display: "flex",
justifyContent: "center",
alignItems: "center",
pb: 4,
pr: 2,
transition: "opacity 0.3s ease, visibility 0.3s ease, margin 0.3s ease"
},
button_text: {
transition: "opacity 0.3s ease, visibility 0.3s ease, margin 0.3s ease",
whiteSpace: "nowrap"
},
collapse_button: {
"& svg": { flexShrink: "0" },
},
},
variants: {
state: {
open: {
root: { width: "190px" },
logo: { justifyContent: "flex-start", ml: 2, textStyle: "4xl" },
footer: { gap: 16, flexDirection: "row" },
button_text: {ml: 3, opacity: 1, visibility: "visible"},
},
closed: {
root: { width: "71px" },
logo: { justifyContent: "center", ml: -1, textStyle: "3xl" },
footer: { gap: 2, flexDirection: "column-reverse" },
button_text: {ml: 0, opacity: 0, visibility: "hidden"},
}
}
} }
}); });