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 51%
rename from src/components/Sidebar.tsx
rename to src/components/sidebar/Sidebar.tsx
index 0d2c64e..d6cd94a 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,29 @@ 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..9b54a93
--- /dev/null
+++ b/src/components/sidebar/SidebarGroup.tsx
@@ -0,0 +1,35 @@
+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) {
+ // eslint-disable-next-line react-hooks/set-state-in-effect
+ 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 78%
rename from src/components/SidebarLink.tsx
rename to src/components/sidebar/SidebarLink.tsx
index b30b12c..ab05271 100644
--- a/src/components/SidebarLink.tsx
+++ b/src/components/sidebar/SidebarLink.tsx
@@ -2,7 +2,7 @@ import { NavLink } from 'react-router-dom';
type SidebarLinkProps = {
label: string;
- icon: React.ReactNode; // TODO: Fix this
+ icon: React.ReactNode;
nav: string;
};
@@ -13,7 +13,7 @@ export default function SidebarLink({ label, icon, nav }: SidebarLinkProps) {
className={({ isActive }) => `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..d6d9656 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,37 @@
display: none;
}
-.main-sidebar-link-container {
+/* Sidebar Workspace */
+
+.sidebar-workspace {
display: flex;
flex-direction: column;
- flex-grow: 1;
- gap: 0.1rem;
+ gap: 0.4rem;
+}
+
+.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;
}
-.sidebar-link {
+.workspace-text {
+ font-size: 0.85rem;
+}
+
+/* Sidebar Links */
+
+.sidebar-link,
+.workspace-header {
display: flex;
flex-direction: row;
align-items: center;
@@ -71,7 +95,7 @@
justify-content: flex-start;
width: 100%;
border-radius: 0.5rem;
- padding: 0.5rem 0.6rem;
+ padding: 0.4rem 0.6rem;
cursor: pointer;
text-decoration: none;
color: var(--standard-text);
@@ -90,17 +114,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 +129,77 @@
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.4rem 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;
+}
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..4c27ae7 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
+
+ >
+ );
+}