From 4aa8eb7ff0a033af297263e64b61796b7fc58faa Mon Sep 17 00:00:00 2001 From: vkuchenik Date: Thu, 3 Sep 2026 14:07:39 -0700 Subject: [PATCH] updated header so all styling is now in the designated themes file --- client/src/App.jsx | 123 ++++++++++----------- client/src/components/layout/Header.jsx | 46 ++++---- client/src/pages/home/Home.jsx | 3 +- client/src/pages/home/tabs/MyDashboard.jsx | 26 ++--- client/src/theme.js | 61 +++++++--- 5 files changed, 144 insertions(+), 115 deletions(-) diff --git a/client/src/App.jsx b/client/src/App.jsx index e507f47..c8a52e0 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,7 +1,7 @@ import 'leaflet/dist/leaflet.css'; -import { useEffect } from 'react'; -import { Routes, Route, Navigate, Outlet } from 'react-router-dom'; -import { useRecipe, Grid, GridItem, useDialog, Flex, Heading } from "@chakra-ui/react"; +import {useEffect} from 'react'; +import {Routes, Route, Navigate, Outlet} from 'react-router-dom'; +import {useRecipe, Grid, GridItem, useDialog, Flex, Heading} from "@chakra-ui/react"; // --- NEW AUTH IMPORTS --- import useAuthStore from './store/authStore'; @@ -19,80 +19,75 @@ import GlobalMap from "./pages/maps/GlobalMap.jsx"; import Admin from "./pages/admin/Admin.jsx"; import MyDashboard from "./pages/home/tabs/MyDashboard.jsx"; +export default function App() { + // 1. Pull the initialization function from Zustand + const checkAuth = useAuthStore((state) => state.checkAuth); + + // 2. Ping Django to verify the HttpOnly cookie the moment the app boots + useEffect(() => { + checkAuth(); + }, [checkAuth]); + + return ( + + {/* --- Public Routes --- */} + }/> + + {/* --- Secure Routes --- */} + }> + + {/* --- Non-Public Routes (Now completely locked down) --- */} + }> + + }> + }/> + }/> + }/> + }/> + }/> + + + }/> + }/> + }/> + }/> + + + + + {/* --- Redirect Routes --- */} + }/> + + ); +} + +// The fundamental layout of the webpage function AppFoundation() { - const recipe = useRecipe({ key: "dashboard" }); + const recipe = useRecipe({key: "dashboard"}); const styles = recipe(); const dialog = useDialog(); return ( <> - - + + - + -
+
- - + + ) } -const Placeholder = ({ name }) => ( - - {name} Dashboard - Coming Soon - -); - -function App() { - // 1. Pull the initialization function from Zustand - const checkAuth = useAuthStore((state) => state.checkAuth); - - // 2. Ping Django to verify the HttpOnly cookie the moment the app boots - useEffect(() => { - checkAuth(); - }, [checkAuth]); - - return ( - - {/* --- Public Routes --- */} - } /> - - {/* --- SECURE ROUTES --- */} - }> - - {/* --- Non-Public Routes (Now completely locked down) --- */} - }> - - }> - } /> - } /> - } /> - } /> - } /> - - - } /> - } /> - } /> - } /> - - - - - {/* --- Redirect Routes --- */} - } /> - - ); -} - -export default App; \ No newline at end of file +// A dummy page that acts as a placeholder for pages that aren't developed yet but are navigatable to +const Placeholder = ({name}) => ( + + {name} Dashboard - Coming Soon + +); \ No newline at end of file diff --git a/client/src/components/layout/Header.jsx b/client/src/components/layout/Header.jsx index 82db471..e2bfa3a 100644 --- a/client/src/components/layout/Header.jsx +++ b/client/src/components/layout/Header.jsx @@ -1,6 +1,5 @@ -import { useRecipe, Button, Stack, Text, Flex } from "@chakra-ui/react" +import {useSlotRecipe, Text, Flex} from "@chakra-ui/react" import UserAvatarMenu from "./UserAvatarMenu.jsx"; -import { NavLink } from "react-router-dom"; import useAuthStore from "@/store/authStore"; import {SearchBar} from "@/components/dashboard/SearchBar.jsx"; @@ -9,27 +8,30 @@ import {SearchBar} from "@/components/dashboard/SearchBar.jsx"; // Accept a 'user' prop now, fallback to placeholder if empty export default function Header() { - const recipe = useRecipe({ key: "header" }); - const styles = recipe(); + const recipe = useSlotRecipe({key: "header"}); + const styles = recipe(); - const { user } = useAuthStore(); - console.log(user); - const displayName = user ? (user.firstName || user.username) : "Loading..."; - const avatarname = user ? (user.fullName || user.username) : "Loading..."; + const {user} = useAuthStore(); + console.log(user); + const displayName = user ? (user.firstName || user.username) : "Loading..."; + const avatarname = user ? (user.fullName || user.username) : "Loading..."; - const displayEmail = user?.email || "LDAP User"; + const displayEmail = user?.email || "LDAP User"; - return ( - - - {/* User Profile Section */} - - {displayName} - - - - ); + return ( + + + + + + {/* User Profile Section */} + + {displayName} + + + + ); } \ No newline at end of file diff --git a/client/src/pages/home/Home.jsx b/client/src/pages/home/Home.jsx index 4f34457..0afeeec 100644 --- a/client/src/pages/home/Home.jsx +++ b/client/src/pages/home/Home.jsx @@ -49,7 +49,6 @@ export default function Home() { {/* The Settings button is now inline with the tabs and only renders on the personal dashboard */} {isPersonalDashboard && } - {/* EDIT MODE BUTTONS & CONTROLS */} @@ -57,9 +56,9 @@ export default function Home() { {/* Future global controls go here */} - + {/* TABS CONTENT */} diff --git a/client/src/pages/home/tabs/MyDashboard.jsx b/client/src/pages/home/tabs/MyDashboard.jsx index aed386f..14a9502 100644 --- a/client/src/pages/home/tabs/MyDashboard.jsx +++ b/client/src/pages/home/tabs/MyDashboard.jsx @@ -13,8 +13,8 @@ import {WIDGET_REGISTRY} from '@/constants/widgetRegistry.jsx'; // React-Grid-Layout requires this wrapper to automatically calculate screen width const ResponsiveGridLayout = WidthProvider(Responsive); -export default function MyDashboard() { +export default function MyDashboard() { // ☁️ Database Connection const {user} = useAuthStore(); @@ -28,25 +28,23 @@ export default function MyDashboard() { // πŸ”’ Safety lock to prevent infinite re-renders const hasHydrated = useRef(false); - // 1. Pull the new global slot recipe + // 1. Pull the global slot recipes const recipe = useSlotRecipe({key: "glassPanel"}); const styles = recipe({ layout: "widget" }); const popoverStyles = recipe({ layout: "popover" }); + // 2. Populate widgets useEffect(() => { if (user?.preferences?.dashboard_layout && !hasHydrated.current) { const savedLayout = user.preferences.dashboard_layout; // Safety check: Only inject if it's actually an array of widgets. // (Prevents a crash if MariaDB returns a default empty object {}) - if (Array.isArray(savedLayout)) { - setWidgets(savedLayout); - } + if (Array.isArray(savedLayout)) setWidgets(savedLayout); hasHydrated.current = true; } }, [user, setWidgets]); - // πŸ› οΈ Format the data for RGL const rglLayout = widgets.map(w => ({ i: w.id, @@ -54,10 +52,10 @@ export default function MyDashboard() { y: w.y, w: w.w, h: w.h, - isResizable: false // 🚫 The magic lock! No resizing allowed globally. + isResizable: false // The magic lock! No resizing allowed globally. })); - // 3. THE COMPONENT MAPPER + // 3. The component mapper const renderWidget = (widget) => { const registryEntry = WIDGET_REGISTRY[widget.type]; @@ -74,7 +72,7 @@ export default function MyDashboard() { {registryEntry.name} - {/* THE SETTINGS ELLIPSIS */} + {/* WIDGET SETTINGS BUTTON (ELLIPSES) */} {SettingsUI ? ( @@ -136,20 +134,20 @@ export default function MyDashboard() { onLayoutChange={(newLayout) => updateLayoutPositions(newLayout)} // Fires when user drops a widget compactType="vertical" // Auto-packs widgets to the top > - {/* 3. 🎨 Paint the Widgets */} + {/* 🎨 Paint the Widgets */} {widgets.map(widget => ( - {/* 4. THE DELETE BUTTON */} + {/* THE DELETE BUTTON */} {isEditing && ( )} - {/* 4. SUSPENSE BOUNDARY wrapping the render function */} + {/* SUSPENSE BOUNDARY wrapping the render function */} diff --git a/client/src/theme.js b/client/src/theme.js index fcb7ae1..c44160e 100644 --- a/client/src/theme.js +++ b/client/src/theme.js @@ -1,17 +1,41 @@ import {defineSlotRecipe, createSystem, defaultConfig, defineConfig, defineRecipe} from "@chakra-ui/react"; -//β€”β€”β€”β€”β€”RECIPESβ€”β€”β€”β€”β€”// -const headerRecipe = defineRecipe({ +// CONSOLIDATED βœ” +const headerRecipe = defineSlotRecipe({ + slots: ["root", "search_bar", "user_info"], base: { - bg: "{transparent}", - color: "text", - width: "100%", - height: "100%", - display: "flex", - flexDirection: "row", - justifyContent: "space-between", - alignItems: "center", - } + root: { + bg: "{transparent}", + color: "text", + width: "100%", + height: "100%", + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + pl: 3, + }, + search_bar: { + width: "100%", + // input element in search bar component + "& input": { + width: "410px", + } + }, + user_info: { + flexDirection: "row", + justifyContent: "flex-end", + alignItems: "center", + gap: 3, + pr: 6, + + // The Text component + "& p": { + fontWeight: "bold", + fontSize:"16px" // equivalent to chakra 'md' + } + } + }, }); // CONSOLIDATED βœ” @@ -208,9 +232,18 @@ const sidebarRecipe = defineSlotRecipe({ } }); +// CONSOLIDATED βœ” const dashboardRecipe = defineRecipe({ base: { - bg: "{MainBackground}" + height: "100vh", + width: "100vw", + bg: "{MainBackground}", + + // selects the third div in the grid layout (the canvas) + "& > div:nth-of-type(3)": { + width: "100%", + overflow: "auto", + } } }); @@ -484,12 +517,12 @@ const config= defineConfig({ }, }, recipes: { - header: headerRecipe, dashboard: dashboardRecipe, canvas: canvasRecipe, glassTab: glassTabRecipe }, slotRecipes: { + header: headerRecipe, sidebar: sidebarRecipe, // widget: widgetRecipe, glassPanel: glassPanelRecipe, @@ -497,4 +530,6 @@ const config= defineConfig({ }, }); + +// Define semantic tokens and export recipes export const system = createSystem(defaultConfig, config); \ No newline at end of file