Group sidebar nav by purpose

Replaces the flat 16-item list with six sections (Overview, Operations,
Vendors, Customers & Sites, Internal, System) and adds section titles
that collapse into dividers when the sidebar is collapsed.
This commit is contained in:
Adam Moussa 2026-04-20 13:49:52 -04:00
parent 2a6fe6f35e
commit a349a58822
2 changed files with 102 additions and 31 deletions

View file

@ -19,29 +19,58 @@ import {
FaFileInvoiceDollar,
} from "react-icons/fa";
const navItems = [
{ label: "Dashboard", icon: <FaTachometerAlt />, path: "/" },
{ label: "Calendar", icon: <FaCalendarAlt />, path: "/calendar" },
{ label: "Documents", icon: <FaFileAlt />, path: "/documents" },
{ label: "Employees", icon: <FaUserTie />, path: "/employees" },
{ label: "Accounts", icon: <FaMoneyCheckAlt />, path: "/accounts" },
{ label: "Contacts", icon: <FaAddressBook />, path: "/contacts" },
{ label: "Reports", icon: <FaChartBar />, path: "/reports" },
{ label: "Work Orders", icon: <FaTools />, path: "/workorders" },
{ label: "Vendors", icon: <FaTruck />, path: "/vendors" },
{ label: "Vendor POs", icon: <FaFileInvoiceDollar />, path: "/vendor-pos" },
{ label: "Uplifts", icon: <FaDollarSign />, path: "/uplifts" },
{ label: "Follow Ups", icon: <FaBell />, path: "/followups" },
{ label: "PM Schedules", icon: <FaClipboardList />, path: "/pmschedules" },
{ label: "Assets", icon: <FaCubes />, path: "/assets" },
{ label: "Locations", icon: <FaMapMarkerAlt />, path: "/locations" },
{ label: "Settings", icon: <FaCog />, path: "/settings/dropdowns" },
const navGroups = [
{
title: "Overview",
items: [
{ label: "Dashboard", icon: <FaTachometerAlt />, path: "/" },
{ label: "Calendar", icon: <FaCalendarAlt />, path: "/calendar" },
{ label: "Reports", icon: <FaChartBar />, path: "/reports" },
],
},
{
title: "Operations",
items: [
{ label: "Work Orders", icon: <FaTools />, path: "/workorders" },
{ label: "Uplifts", icon: <FaDollarSign />, path: "/uplifts" },
{ label: "Follow Ups", icon: <FaBell />, path: "/followups" },
{ label: "PM Schedules", icon: <FaClipboardList />, path: "/pmschedules" },
],
},
{
title: "Vendors",
items: [
{ label: "Vendors", icon: <FaTruck />, path: "/vendors" },
{ label: "Vendor POs", icon: <FaFileInvoiceDollar />, path: "/vendor-pos" },
],
},
{
title: "Customers & Sites",
items: [
{ label: "Accounts", icon: <FaMoneyCheckAlt />, path: "/accounts" },
{ label: "Contacts", icon: <FaAddressBook />, path: "/contacts" },
{ label: "Locations", icon: <FaMapMarkerAlt />, path: "/locations" },
{ label: "Assets", icon: <FaCubes />, path: "/assets" },
],
},
{
title: "Internal",
items: [
{ label: "Employees", icon: <FaUserTie />, path: "/employees" },
{ label: "Documents", icon: <FaFileAlt />, path: "/documents" },
],
},
{
title: "System",
items: [
{ label: "Settings", icon: <FaCog />, path: "/settings/dropdowns" },
],
},
];
export default function Sidebar() {
return (
<aside className="sidebar">
{/* Logo */}
<div className="logoRow">
<img
src="/logo.png"
@ -50,20 +79,30 @@ export default function Sidebar() {
/>
</div>
<div className="navTitle">NAVIGATION</div>
<ul className="navList">
{navItems.map(({ label, icon, path }) => (
<li key={path}>
<NavLink
to={path}
className={({ isActive }) =>
`navItem ${isActive ? "active" : ""}`
}
{navGroups.map((group, idx) => (
<li key={group.title} className="navGroup">
<div
className={`navGroupTitle ${idx === 0 ? "navGroupTitleFirst" : ""}`}
>
<span className="glyph">{icon}</span>
<span className="navLabel">{label}</span>
</NavLink>
{group.title}
</div>
<ul className="navGroupList">
{group.items.map(({ label, icon, path }) => (
<li key={path}>
<NavLink
to={path}
end={path === "/"}
className={({ isActive }) =>
`navItem ${isActive ? "active" : ""}`
}
>
<span className="glyph">{icon}</span>
<span className="navLabel">{label}</span>
</NavLink>
</li>
))}
</ul>
</li>
))}
</ul>

View file

@ -106,6 +106,31 @@ body {
margin-bottom: 14px;
}
.navGroup {
list-style: none;
}
.navGroupList {
list-style: none;
padding: 0;
margin: 0;
}
.navGroupTitle {
font-size: 11px;
font-weight: 600;
letter-spacing: 1.2px;
text-transform: uppercase;
color: #9aa0a6;
margin-top: 18px;
margin-bottom: 6px;
padding: 0 14px;
}
.navGroupTitleFirst {
margin-top: 0;
}
.navList {
list-style: none;
padding: 0;
@ -167,10 +192,17 @@ body {
/* Hide text only */
.app.nav-collapsed .navLabel,
.app.nav-collapsed .logoText,
.app.nav-collapsed .navTitle {
.app.nav-collapsed .navTitle,
.app.nav-collapsed .navGroupTitle {
display: none;
}
.app.nav-collapsed .navGroup + .navGroup {
border-top: 1px solid #e5e7eb;
margin-top: 8px;
padding-top: 8px;
}
/* Center icons */
.app.nav-collapsed .navItem {
justify-content: center;