From 0c8820d1098835410f34fd3039b3fad5ddb9a6e8 Mon Sep 17 00:00:00 2001 From: vkuchenik Date: Fri, 11 Sep 2026 14:45:39 -0700 Subject: [PATCH] wip moving menu nav buttons in widget menu --- .../components/dashboard/SettingsButton.jsx | 92 +++---- client/src/pages/home/tabs/MyDashboard.jsx | 29 +-- client/src/theme.js | 237 ++++++++++++++++-- 3 files changed, 253 insertions(+), 105 deletions(-) diff --git a/client/src/components/dashboard/SettingsButton.jsx b/client/src/components/dashboard/SettingsButton.jsx index 751397f..e530565 100644 --- a/client/src/components/dashboard/SettingsButton.jsx +++ b/client/src/components/dashboard/SettingsButton.jsx @@ -31,20 +31,23 @@ export function SettingsButton() { const cancelEdit = useDashboardStore(state => state.cancelEdit); const addWidget = useDashboardStore(state => state.addWidget); - const recipe = useRecipe({key: "glassTab"}); - const tabStyles = recipe(); + const glassTabRecipe = useRecipe({key: "glassTab"}); + const settingsButtonRecipe = useRecipe({key: "settingsButton"}); + const tabStyles = glassTabRecipe(); + const settingsButtonStyles = settingsButtonRecipe(); + + const [canScrollLeft, setCanScrollLeft] = useState(false); + const [canScrollRight, setCanScrollRight] = useState(false); // Pull the glass container styles for the dropdown and modal const panelRecipe = useSlotRecipe({key: "glassPanel"}); const panelStyles = panelRecipe({layout: "dropdown"}); - const modalStyles = panelRecipe({layout: "popover"}); + const modalStyles = panelRecipe({layout: "popover", leftScroll: canScrollLeft ? "visible" : "hidden", rightScroll: canScrollRight ? "visible" : "hidden"}); const [isLibraryOpen, setIsLibraryOpen] = useState(false); // ⬅️ ➡️ This is the callbacks and scroll control to add the chevron arrows in the tab list const tabsRef = useRef(null); - const [canScrollLeft, setCanScrollLeft] = useState(false); - const [canScrollRight, setCanScrollRight] = useState(false); const checkScroll = useCallback(() => { if (tabsRef.current) { @@ -92,7 +95,7 @@ export function SettingsButton() { <> {isEditing ? ( // 📝 EDIT MODE: The 3-Pill Layout - + {/* 1. The Add Widget Button */} - {/* size increased to 24 to match tabs. flexShrink: 0 is CRITICAL */} + {/* settings icon size set to 24 to match tabs. flexShrink 0 is CRITICAL */} Dashboard Settings @@ -174,27 +177,24 @@ export function SettingsButton() { setIsLibraryOpen(e.open)} - size="xl" - placement="center" closeOnInteractOutside={true} closeOnEscapeKeyDown={true} + size="xl" + placement="center" > {/* Soft blur can be added to the background behind the modal */} {/**/} - - - - - Widgets Shop + + + Widgets Shop - + - - - {/* LEFT GLASS CRESCENT */} + {/* HORIZONTAL SCROLLABLE MENU OF WIDGET CATEGORIES */} + + {/* left glass crescent */} {canScrollLeft && ( )} - { - if (e.currentTarget) { - e.currentTarget.scrollLeft += e.deltaY; - } - }} + + {/* the categories */} + { if (e.currentTarget) e.currentTarget.scrollLeft += e.deltaY; }} > {categories.map(cat => ( - + {cat} ))} + + {/* right glass crescent */} {canScrollRight && ( )} - + + {/* THE WIDGET OPTIONS W/IN EACH CATEGORY */} {categories.map(cat => ( diff --git a/client/src/pages/home/tabs/MyDashboard.jsx b/client/src/pages/home/tabs/MyDashboard.jsx index 14a9502..aa95e62 100644 --- a/client/src/pages/home/tabs/MyDashboard.jsx +++ b/client/src/pages/home/tabs/MyDashboard.jsx @@ -68,28 +68,21 @@ export default function MyDashboard() { return ( <> - + {registryEntry.name} {/* WIDGET SETTINGS BUTTON (ELLIPSES) */} - {SettingsUI ? ( + {SettingsUI && ( - + {/* NEW: The Positioner lifts the content out of the Flexbox flow */} - + }> - ) : ( - )} @@ -131,8 +122,8 @@ export default function MyDashboard() { rowHeight={30} isDraggable={isEditing} // Only allows dragging when Settings tools toggle this isResizable={false} // Double lock-down - onLayoutChange={(newLayout) => updateLayoutPositions(newLayout)} // Fires when user drops a widget compactType="vertical" // Auto-packs widgets to the top + onLayoutChange={(newLayout) => updateLayoutPositions(newLayout)} // Fires when user drops a widget > {/* 🎨 Paint the Widgets */} {widgets.map(widget => ( @@ -151,17 +142,7 @@ export default function MyDashboard() { {isEditing && ( removeWidget(widget.id)} onMouseDown={(e) => e.stopPropagation()} // 🚫 Stops RGL from grabbing the widget onTouchStart={(e) => e.stopPropagation()} // 🚫 Same protection for mobile touches diff --git a/client/src/theme.js b/client/src/theme.js index 4e0f21e..9d5ed29 100644 --- a/client/src/theme.js +++ b/client/src/theme.js @@ -97,9 +97,11 @@ const sidebarRecipe = defineSlotRecipe({ _hover: { bg: "rgba(255, 255, 255, 0.2)", color: "{text}", - fontWeight: "500", "& svg": { strokeWidth: "3" + }, + "& span": { + fontWeight: "700", } }, @@ -119,9 +121,11 @@ const sidebarRecipe = defineSlotRecipe({ _hover: { bg: "{MainBackground}", color: "{textInverted}", - fontWeight: "normal", "& svg": { strokeWidth: "2" // Keeps the active icon at normal thickness on hover + }, + "& span": { + fontWeight: "500", } }, @@ -181,7 +185,7 @@ const sidebarRecipe = defineSlotRecipe({ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "clip", - fontWeight: "500" + fontWeight: "500", }, collapse_button: { "& svg": {flexShrink: "0"}, @@ -244,14 +248,7 @@ const dashboardRecipe = defineRecipe({ } }); -const canvasRecipe = defineRecipe({ - base: { - bg: "{transparent}", - zIndex: "-1", - color: "{text}" - } -}); - +// CONSOLIDATED ✔ const homeRecipe = defineSlotRecipe({ slots: ["root"], base: { @@ -291,6 +288,30 @@ const homeRecipe = defineSlotRecipe({ }, }) +const settingsButtonRecipe = defineSlotRecipe({ + slots: ["root", "dialog"], + base: { + root: { + gap: 2, + + "& > button": { + + } + }, + dialog: { + + } + } +}) + +// const canvasRecipe = defineRecipe({ +// base: { +// bg: "{transparent}", +// zIndex: "-1", +// color: "{text}" +// } +// }); + // const widgetRecipe = defineSlotRecipe({ // slots: ["root", "header", "canvas"], // base: { @@ -329,6 +350,9 @@ const homeRecipe = defineSlotRecipe({ // } // }); +// USED IN COMPONENTS: +// * Settings Button +// * My Dashboard const glassPanelRecipe = defineSlotRecipe({ slots: ["root", "header", "body"], @@ -352,26 +376,202 @@ const glassPanelRecipe = defineSlotRecipe({ variants: { layout: { widget: { - root: {width: "100%", height: "100%", borderRadius: "3xl"}, - header: {display: "flex", justifyContent: "space-between", alignItems: "center", px: 3, pt: 2, pb: 0}, - body: {flex: "1", overflow: "hidden", position: "relative", px: 1, pb: 1, pt: 0} + root: { + width: "100%", + height: "100%", + borderRadius: "3xl", + + "& > button": { + position: "absolute", + top: 2, + right: 2, + // size="xs", + bg: "white", + color: "black", + border: "1px solid", + borderRadius: "xl", + borderColor: "gray.200", + _hover: { + bg: "red.50", + color: "red.500", + borderColor: "red.200" + }, + zIndex: 2, + } + }, + header: { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + px: 3, + pt: 2, + pb: 0, + + "& > p": { + color: "titleColor", + fontWeight: "500", + fontSize: "16px", + + // the following three specifications are equivalent to Chakra's 'truncate' prop + whiteSpace: "nowrap", + overflow: "hidden", + textOverflow: "clip", + }, + + "& > button": { + borderRadius: "xl", + + _hover: { + color: "white", + bg: "gray.500", + }, + } + }, + body: { + flex: "1", + overflow: "hidden", + position: "relative", + px: 1, + pb: 1, + pt: 0 + } }, dropdown: { - root: {borderRadius: "xl", p: 1} + root: { + borderRadius: "xl", + p: 1 + } // (Header and body slots are ignored here because dropdowns don't use them) }, popover: { root: { borderRadius: "2xl", - p: 4, + p: 0, boxShadow: "xl", minW: "240px", + maxW: "60%", + minH: "80%", + overflow: "hidden", // OVERRIDES: Make the background 85-90% opaque instead of 40% - bg: {base: "rgba(255, 255, 255, 0.75)", _dark: "rgba(20, 22, 25, 0.8)"}, + bg: { + base: "rgba(255, 255, 255, 0.75)", + _dark: "rgba(20, 22, 25, 0.8)" + }, // OVERRIDES: Increase the blur just to smooth out any stubborn gridlines backdropFilter: "blur(15px)", WebkitBackdropFilter: "blur(15px)", + + // dialog header + "& > div.chakra-dialog__header": { + bg: "transparent", + color: { + base: "gray.800", + _dark: "white" + }, + py: 4, + borderColor: { + base: "gray.200", + _dark: "whiteAlpha.200" + }, + + // title + "& h2": { + fontSize: "xl", + fontWeight: "bold" + }, + }, + + // dialog body + "& > div.chakra-dialog__body": { + p: 0, + + // everything below is specific to the widget menu found in the settings button component + // the horizontal widget categories menu + "& div.chakra-tabs__list": { + bg: { + base: "rgba(0, 0, 0, 0.04)", + _dark: "rgba(255, 255, 255, 0.05)" + }, + p: 1, + borderRadius: "full", + display: "flex", + flexWrap: "nowrap", + overflowX: "auto", + maxW: "100%", + border: "1px solid", + borderColor: { + base: "blackAlpha.50", + _dark: "whiteAlpha.100" + }, + scrollbarWidth: "none", + "&::-webkit-scrollbar": {display: "none"}, + + "& button.chakra-tabs__trigger": { + px: 5, + py: 2, + borderRadius: "full", + whiteSpace: "nowrap", + flexShrink: 0, + color: { + base: "gray.500", + _dark: "gray.400" + }, + fontWeight: "medium", + transition: "background-color 0.2s, color 0.2s, box-shadow 0.2s", + _hover: { + color: { + base: "gray.800", + _dark: "gray.200" + }, + }, + _selected: { + bg: { + base: "white", + _dark: "rgba(255, 255, 255, 0.12)" + }, + color: { + base: "blue.600", + _dark: "blue.200" + }, + boxShadow: "sm", + fontWeight: "bold", + } + } + }, + + // "& div.chakra-tabs__root > div:first-child div > svg": { + // position: "absolute", + // top: "0", + // bottom: "0", + // w: "50px", + // align: "center", + // justify: "center", + // zIndex: 2, + // cursor: "pointer", + // bg: { + // base: "rgba(255, 255, 255, 0.7)", + // _dark: "rgba(30, 30, 30, 0.8)" + // }, + // backdropFilter: "blur(1px)", + // + // color: { + // base: "gray.600", + // _dark: "gray.300" + // }, + // transition: "background-color 0.2s", + // _hover: { + // color: { + // base: "blue.500", + // _dark: "blue.300" + // }, + // bg: { + // base: "rgba(255, 255, 255, 0.9)", + // _dark: "rgba(40, 40, 40, 0.95)" + // }, + // } + // } + } } } }, @@ -554,7 +754,7 @@ const config = defineConfig({ }, recipes: { dashboard: dashboardRecipe, - canvas: canvasRecipe, + // canvas: canvasRecipe, glassTab: glassTabRecipe }, slotRecipes: { @@ -563,6 +763,7 @@ const config = defineConfig({ // widget: widgetRecipe, glassPanel: glassPanelRecipe, home: homeRecipe, + settingsButton: settingsButtonRecipe, }, }, });