From db7f2a304a870b9f89cd718cdbfd45960f1cfaf6 Mon Sep 17 00:00:00 2001 From: JManion32 Date: Sun, 15 Feb 2026 15:22:14 -0500 Subject: [PATCH 1/2] Polished Sidebar --- src/App.tsx | 8 +- src/components/AppLayout.tsx | 4 +- src/components/DarkModeToggle.tsx | 2 +- src/components/Header.tsx | 22 ---- src/components/{ => sidebar}/Sidebar.tsx | 25 ++-- src/components/sidebar/SidebarGroup.tsx | 38 ++++++ src/components/{ => sidebar}/SidebarLink.tsx | 6 +- src/components/sidebar/SidebarProfile.tsx | 20 ++++ src/components/sidebar/SidebarWorkspace.tsx | 27 +++++ src/css/colors.css | 8 +- src/css/header.css | 52 --------- src/css/index.css | 3 + src/css/sidebar.css | 116 ++++++++++++++++--- src/pages/{Events.tsx => HelpCenter.tsx} | 4 +- src/pages/Settings.tsx | 3 + src/pages/events/CreateEvent.tsx | 9 ++ src/pages/events/EventHistory.tsx | 9 ++ 17 files changed, 241 insertions(+), 115 deletions(-) delete mode 100644 src/components/Header.tsx rename src/components/{ => sidebar}/Sidebar.tsx (56%) create mode 100644 src/components/sidebar/SidebarGroup.tsx rename src/components/{ => sidebar}/SidebarLink.tsx (64%) create mode 100644 src/components/sidebar/SidebarProfile.tsx create mode 100644 src/components/sidebar/SidebarWorkspace.tsx delete mode 100644 src/css/header.css rename src/pages/{Events.tsx => HelpCenter.tsx} (51%) create mode 100644 src/pages/events/CreateEvent.tsx create mode 100644 src/pages/events/EventHistory.tsx diff --git a/src/App.tsx b/src/App.tsx index 8183866..51e9225 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,12 +4,14 @@ import AppLayout from './components/AppLayout.tsx'; import Home from './pages/Home.tsx'; import Register from './pages/Register.tsx'; import Dashboard from './pages/Dashboard.tsx'; -import Events from './pages/Events.tsx'; +import CreateEvent from './pages/events/CreateEvent.tsx'; +import EventHistory from './pages/events/EventHistory.tsx'; import Calendar from './pages/Calendar.tsx'; import Roster from './pages/Roster.tsx'; import Notifications from './pages/Notifications.tsx'; import Profile from './pages/Profile.tsx'; import Settings from './pages/Settings.tsx'; +import HelpCenter from './pages/HelpCenter.tsx'; function App() { return ( @@ -21,12 +23,14 @@ function App() { } /> }> } /> - } /> + } /> + } /> } /> } /> } /> } /> } /> + } /> diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx index 94721c2..5e57c80 100644 --- a/src/components/AppLayout.tsx +++ b/src/components/AppLayout.tsx @@ -3,8 +3,7 @@ import '../css/app-layout.css'; import { Outlet } from 'react-router-dom'; import { useCollapseSidebar } from '../hooks/useCollapseSidebar'; -import Header from './Header.tsx'; -import Sidebar from './Sidebar.tsx'; +import Sidebar from './sidebar/Sidebar.tsx'; export default function AppLayout() { const [collapsed, setCollapsed] = useCollapseSidebar('sidebar-collapsed', false); @@ -15,7 +14,6 @@ export default function AppLayout() { return (
-
diff --git a/src/components/DarkModeToggle.tsx b/src/components/DarkModeToggle.tsx index fb64f7b..af19af0 100644 --- a/src/components/DarkModeToggle.tsx +++ b/src/components/DarkModeToggle.tsx @@ -1,6 +1,6 @@ import { useTheme } from '../contexts/ThemeContext'; -export function DarkModeToggle() { +export default function DarkModeToggle() { const { theme, toggleTheme } = useTheme(); return ( diff --git a/src/components/Header.tsx b/src/components/Header.tsx deleted file mode 100644 index 9114a1a..0000000 --- a/src/components/Header.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import '../css/header.css'; -import { useNavigate } from 'react-router-dom'; -import { DarkModeToggle } from './DarkModeToggle.tsx'; - -export default function Header() { - const navigate = useNavigate(); - - return ( - - ); -} diff --git a/src/components/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx similarity index 56% rename from src/components/Sidebar.tsx rename to src/components/sidebar/Sidebar.tsx index 0d2c64e..bd1b2e3 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -1,16 +1,21 @@ -import '../css/sidebar.css'; +import '../../css/sidebar.css'; +import SidebarGroup from './SidebarGroup.tsx'; import SidebarLink from './SidebarLink.tsx'; +import SidebarProfile from './SidebarProfile.tsx'; +import SidebarWorkspace from './SidebarWorkspace.tsx'; -// Icon Imports import { Bars3Icon, HomeIcon, StarIcon, + PlusIcon, + ClipboardDocumentCheckIcon, CalendarDaysIcon, UserGroupIcon, BellAlertIcon, UserCircleIcon, Cog8ToothIcon, + QuestionMarkCircleIcon, } from '@heroicons/react/24/solid'; type SidebarProps = { @@ -27,17 +32,21 @@ export default function Sidebar({ collapsed, onToggle }: SidebarProps) {
-
+ } nav="/dashboard" /> - } nav="/events" /> + } collapsed={collapsed}> + } nav="/events/create" /> + } nav="/events/history" /> + } nav="/calendar" /> } nav="/roster" /> } nav="/notifications" /> -
-
- } nav="/profile" /> + + + } nav="/help" /> } nav="/settings" /> -
+ } name="Kevin Smith" email="smithk@rpi.edu"/> +
); } diff --git a/src/components/sidebar/SidebarGroup.tsx b/src/components/sidebar/SidebarGroup.tsx new file mode 100644 index 0000000..63461d6 --- /dev/null +++ b/src/components/sidebar/SidebarGroup.tsx @@ -0,0 +1,38 @@ +import { ChevronRightIcon, ChevronDownIcon } from '@heroicons/react/24/solid'; +import { useState, useEffect } from 'react'; + +type SidebarGroupProps = { + label: string; + icon: React.ReactNode; + children: React.ReactNode; + collapsed: boolean; +}; + +export default function SidebarGroup({ label, icon, children, collapsed }: SidebarGroupProps) { + const [open, setOpen] = useState(true); + const Icon = open ? ChevronDownIcon : ChevronRightIcon; + + // This logic assumes the user wants groups back open when sidebar is toggled. + useEffect(() => { + if (collapsed) { + setOpen(false); + } else { + setOpen(true); + } + }, [collapsed]); + + return ( +
+
setOpen((prev) => !prev)}> + {icon} + {label} + +
+ {open && ( +
+ {children} +
+ )} +
+ ); +} diff --git a/src/components/SidebarLink.tsx b/src/components/sidebar/SidebarLink.tsx similarity index 64% rename from src/components/SidebarLink.tsx rename to src/components/sidebar/SidebarLink.tsx index b30b12c..b109e2b 100644 --- a/src/components/SidebarLink.tsx +++ b/src/components/sidebar/SidebarLink.tsx @@ -2,18 +2,18 @@ import { NavLink } from 'react-router-dom'; type SidebarLinkProps = { label: string; - icon: React.ReactNode; // TODO: Fix this + icon: React.ReactNode; nav: string; }; -export default function SidebarLink({ label, icon, nav }: SidebarLinkProps) { +export default function SidebarLink({ label, icon, nav}: SidebarLinkProps) { return ( `sidebar-link ${isActive ? 'active-link' : ''}`} > {icon} - {label} + {label} ); } diff --git a/src/components/sidebar/SidebarProfile.tsx b/src/components/sidebar/SidebarProfile.tsx new file mode 100644 index 0000000..5757d79 --- /dev/null +++ b/src/components/sidebar/SidebarProfile.tsx @@ -0,0 +1,20 @@ +import { useNavigate } from 'react-router-dom'; + +type SidebarLinkProps = { + icon: React.ReactNode; + name: string; + email: string; +}; + +export default function SidebarProfile({ icon, name, email }: SidebarLinkProps) { + const navigate = useNavigate(); + return ( +
navigate('/profile')}> + {icon} +
+ {name} + {email} +
+
+ ); +} diff --git a/src/components/sidebar/SidebarWorkspace.tsx b/src/components/sidebar/SidebarWorkspace.tsx new file mode 100644 index 0000000..2193932 --- /dev/null +++ b/src/components/sidebar/SidebarWorkspace.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useState } from 'react'; + +import { ChevronRightIcon, ChevronDownIcon } from '@heroicons/react/24/solid'; + +interface SidebarWorkspaceProps { + workspace?: string; + children: React.ReactNode; +} + +export default function SidebarWorkspace({ workspace, children }: SidebarWorkspaceProps) { + const [open, setOpen] = useState(true); + const Icon = open ? ChevronDownIcon : ChevronRightIcon; + + return ( +
+
setOpen((prev) => !prev)} + className={`${workspace ? 'workspace-header' : 'hide'}`} + > + + {workspace} +
+ {open && children} +
+ ); +} diff --git a/src/css/colors.css b/src/css/colors.css index db80eeb..66f68f7 100644 --- a/src/css/colors.css +++ b/src/css/colors.css @@ -42,8 +42,7 @@ mode section as well. --standard-black: var(--off-black); --standard-text: var(--primary); - /* Sidebar / Header */ - --header-bg: var(--highlight); + /* Sidebar */ --sidebar-bg: var(--highlight); --sidebar-link-hover-bg: var(--off-white); --sidebar-active-link-bg: var(--primary-light); @@ -56,10 +55,9 @@ mode section as well. --site-bg: var(--off-black); --standard-white: var(--off-black); --standard-black: var(--off-white); - --standard-text: var(--primary); + --standard-text: var(--off-white); - /* Sidebar / Header */ - --header-bg: var(--primary-extra-dark); + /* Sidebar */ --sidebar-bg: var(--primary-extra-dark); --sidebar-link-hover-bg: var(--accent); --sidebar-active-link-bg: var(--accent); diff --git a/src/css/header.css b/src/css/header.css deleted file mode 100644 index 2bd68a4..0000000 --- a/src/css/header.css +++ /dev/null @@ -1,52 +0,0 @@ -.header-container { - display: flex; - flex-direction: row; - gap: 2rem; - align-items: center; - width: 100%; - background: var(--header-bg); - height: 5rem; - margin: 0 0 1rem; - padding: 1rem 2rem 1rem 1rem; - box-shadow: 0 3px 6px rgb(0 0 0 / 15%); - color: var(--standard-text); -} - -.header-title { - margin: 0; - flex-grow: 1; - font-weight: 500; -} - -.header-right-btns { - display: flex; - flex-direction: row; - gap: 1.75rem; - align-items: center; -} - -.profile-btn, -.register-btn { - cursor: pointer; - font-size: 1.25rem; - padding: 0.35rem 1rem; - border-radius: 0.7rem; - display: flex; - align-items: center; - transition: var(--site-transition); -} - -.profile-btn { - background: var(--standard-text); - color: var(--standard-white); -} - -.register-btn { - border-radius: 0.7rem; - border: 2px solid var(--standard-text); -} - -.register-btn:hover { - background: var(--standard-text); - color: var(--standard-white); -} diff --git a/src/css/index.css b/src/css/index.css index fa92217..9249a0b 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -40,3 +40,6 @@ h1 { /* END OF RANDOM AUTO-GENERATED STYLES */ /* ================================================= */ +.hide { + display: none; +} diff --git a/src/css/sidebar.css b/src/css/sidebar.css index 6ed559c..871f999 100644 --- a/src/css/sidebar.css +++ b/src/css/sidebar.css @@ -1,5 +1,6 @@ /* Styles for Sidebar.tsx and SidebarButton.tsx */ +/* Main Sidebar */ .sidebar { display: flex; flex-direction: column; @@ -18,7 +19,7 @@ display: flex; flex-direction: row; width: 100%; - padding: 1rem 0; + padding: 0.75rem 0; justify-content: center; } @@ -56,14 +57,36 @@ display: none; } -.main-sidebar-link-container { +/* Sidebar Workspace */ + +.sidebar-workspace { display: flex; flex-direction: column; - flex-grow: 1; - gap: 0.1rem; + gap: 0.40rem; +} + +.sidebar-workspace:not(:last-child) { + margin-bottom: 1rem; +} + +.sidebar-workspace:last-child { + margin-top: auto; +} + +.workspace-icon { + height: 0.85rem; + width: 0.85rem; + margin-left: 0.2rem; + flex-shrink: 0; +} + +.workspace-text { + font-size: 0.85rem; } -.sidebar-link { +/* Sidebar Links */ + +.sidebar-link, .workspace-header { display: flex; flex-direction: row; align-items: center; @@ -71,7 +94,7 @@ justify-content: flex-start; width: 100%; border-radius: 0.5rem; - padding: 0.5rem 0.6rem; + padding: 0.40rem 0.6rem; cursor: pointer; text-decoration: none; color: var(--standard-text); @@ -90,17 +113,6 @@ .sidebar-link-label { font-size: 1rem; - max-width: 200px; - overflow: hidden; - white-space: nowrap; - transition: - max-width 300ms ease, - opacity 150ms ease 50ms; -} - -.sidebar.collapsed .sidebar-link-label { - max-width: 0; - opacity: 0; } .sidebar-link-icon { @@ -116,3 +128,73 @@ width: 100%; height: 100%; } + + +/* Sidebar Groups */ + +.sidebar-group-header { + display: flex; + flex-direction: row; + align-items: center; + gap: 0.7rem; + justify-content: flex-start; + width: 100%; + border-radius: 0.5rem; + padding: 0.40rem 0.6rem; + cursor: pointer; + text-decoration: none; + color: var(--standard-text); + overflow: hidden; + white-space: nowrap; + transition: none; +} + +.group-collapse-icon { + margin-left: auto; + height: 1rem; + width: 1rem; +} + +.sidebar-group-children { + display: flex; + flex-direction: column; + border-left: 1px solid var(--standard-text); + margin-left: 1.225rem; + padding-left: 1rem; +} + +/* Sidebar Profile */ + +.sidebar-profile-icon { + width: 2rem; + height: 2rem; + flex-shrink: 0; + transition: width 300ms ease, height 300ms ease; +} + +.sidebar.collapsed .sidebar-profile-icon { + width: 1.25rem; + height: 1.25rem; +} + +.sidebar-profile-content { + display: flex; + flex-direction: column; +} + +.sidebar-profile-email { + font-size: 0.75rem; +} +/* Transitions */ + +.sidebar-label-transition { + max-width: 200px; + overflow: hidden; + white-space: nowrap; + transition: max-width 300ms ease, opacity 150ms ease 50ms; +} + +.sidebar.collapsed .sidebar-label-transition { + max-width: 0; + opacity: 0; +} \ No newline at end of file diff --git a/src/pages/Events.tsx b/src/pages/HelpCenter.tsx similarity index 51% rename from src/pages/Events.tsx rename to src/pages/HelpCenter.tsx index aedddef..7de4fdd 100644 --- a/src/pages/Events.tsx +++ b/src/pages/HelpCenter.tsx @@ -1,8 +1,8 @@ -export default function Events() { +export default function HelpCenter() { return ( <>
-

My Events

+

Help Center

); diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 032ebb3..9968320 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -1,8 +1,11 @@ +import DarkModeToggle from '../components/DarkModeToggle' + export default function Settings() { return ( <>

Settings

+
); diff --git a/src/pages/events/CreateEvent.tsx b/src/pages/events/CreateEvent.tsx new file mode 100644 index 0000000..4c50c3c --- /dev/null +++ b/src/pages/events/CreateEvent.tsx @@ -0,0 +1,9 @@ +export default function CreateEvent() { + return ( + <> +
+

Create Event

+
+ + ); +} diff --git a/src/pages/events/EventHistory.tsx b/src/pages/events/EventHistory.tsx new file mode 100644 index 0000000..13ffe34 --- /dev/null +++ b/src/pages/events/EventHistory.tsx @@ -0,0 +1,9 @@ +export default function EventHistory() { + return ( + <> +
+

Event History

+
+ + ); +} From 9c5ae3a6c0e5f6da8eaa2edb93cbf45c0c0e72f8 Mon Sep 17 00:00:00 2001 From: JManion32 Date: Sun, 15 Feb 2026 18:57:52 -0500 Subject: [PATCH 2/2] Fixed lint --- src/components/sidebar/Sidebar.tsx | 14 +++++++++++--- src/components/sidebar/SidebarGroup.tsx | 7 ++----- src/components/sidebar/SidebarLink.tsx | 2 +- src/css/sidebar.css | 23 ++++++++++++++--------- src/pages/Settings.tsx | 4 ++-- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index bd1b2e3..d6cd94a 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -34,9 +34,13 @@ export default function Sidebar({ collapsed, onToggle }: SidebarProps) {
} nav="/dashboard" /> - } collapsed={collapsed}> + } collapsed={collapsed}> } nav="/events/create" /> - } nav="/events/history" /> + } + nav="/events/history" + /> } nav="/calendar" /> } nav="/roster" /> @@ -45,7 +49,11 @@ export default function Sidebar({ collapsed, onToggle }: SidebarProps) { } nav="/help" /> } nav="/settings" /> - } name="Kevin Smith" email="smithk@rpi.edu"/> + } + name="Kevin Smith" + email="smithk@rpi.edu" + /> ); diff --git a/src/components/sidebar/SidebarGroup.tsx b/src/components/sidebar/SidebarGroup.tsx index 63461d6..9b54a93 100644 --- a/src/components/sidebar/SidebarGroup.tsx +++ b/src/components/sidebar/SidebarGroup.tsx @@ -15,6 +15,7 @@ export default function SidebarGroup({ label, icon, children, collapsed }: Sideb // This logic assumes the user wants groups back open when sidebar is toggled. useEffect(() => { if (collapsed) { + // eslint-disable-next-line react-hooks/set-state-in-effect setOpen(false); } else { setOpen(true); @@ -28,11 +29,7 @@ export default function SidebarGroup({ label, icon, children, collapsed }: Sideb {label} - {open && ( -
- {children} -
- )} + {open &&
{children}
} ); } diff --git a/src/components/sidebar/SidebarLink.tsx b/src/components/sidebar/SidebarLink.tsx index b109e2b..ab05271 100644 --- a/src/components/sidebar/SidebarLink.tsx +++ b/src/components/sidebar/SidebarLink.tsx @@ -6,7 +6,7 @@ type SidebarLinkProps = { nav: string; }; -export default function SidebarLink({ label, icon, nav}: SidebarLinkProps) { +export default function SidebarLink({ label, icon, nav }: SidebarLinkProps) { return (

Settings

- +
);