Skip to content

Commit 797f4d0

Browse files
committed
fix: drop the parent's filled pill when an admin sidebar sub-item is active
Both the Services parent and the Catalog leaf use href `/admin/services`, so MUI's `selected` prop turned both into the same filled teal pill stacked directly on top of each other — visually a single mass with two halves of identical colour. Add a `sectionActive` mode for the parent NavLink: when one of its sub-items is the deepest match, suppress the filled background and instead render with bold + accent-coloured text and icon. The leaf sub-item is now the only entry that draws the eye, while the parent still reads as "this is the section you're in".
1 parent 2c482ea commit 797f4d0

1 file changed

Lines changed: 46 additions & 17 deletions

File tree

apps/web/src/components/admin/AdminSidebar.tsx

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,38 @@ interface AdminSidebarProps {
115115
selfHosted?: boolean;
116116
}
117117

118-
function NavLink({ item, active }: { item: NavItem; active: boolean }) {
118+
function NavLink({
119+
item,
120+
active,
121+
sectionActive = false,
122+
}: {
123+
item: NavItem;
124+
active: boolean;
125+
/**
126+
* True when this entry is the parent of an active sub-item but not itself
127+
* the deepest match. Renders as a muted "section header" (bold text, no
128+
* filled pill) so the active sub-item below stays the visual focus instead
129+
* of stacking two identical pills.
130+
*/
131+
sectionActive?: boolean;
132+
}) {
133+
// The leaf (Mui-selected) styling and the section-active styling are
134+
// mutually exclusive — `selected` flips MUI's filled background, which is
135+
// what we explicitly want to avoid for `sectionActive`.
136+
const showFilled = active && !sectionActive;
119137
return (
120138
<ListItem disablePadding>
121139
<ListItemButton
122140
component={Link}
123141
href={item.href}
124-
selected={active}
142+
selected={showFilled}
125143
sx={{
126144
borderRadius: 1,
127145
mx: 1,
146+
...(sectionActive && {
147+
color: "primary.main",
148+
"& .MuiListItemIcon-root": { color: "primary.main" },
149+
}),
128150
"&.Mui-selected": {
129151
bgcolor: "primary.main",
130152
color: "primary.contrastText",
@@ -136,7 +158,10 @@ function NavLink({ item, active }: { item: NavItem; active: boolean }) {
136158
<ListItemIcon sx={{ minWidth: 36 }}>{item.icon}</ListItemIcon>
137159
<ListItemText
138160
primary={item.label}
139-
primaryTypographyProps={{ fontSize: 14, fontWeight: active ? 600 : 400 }}
161+
primaryTypographyProps={{
162+
fontSize: 14,
163+
fontWeight: active || sectionActive ? 600 : 400,
164+
}}
140165
/>
141166
</ListItemButton>
142167
</ListItem>
@@ -200,20 +225,24 @@ export function AdminSidebar({ open, onClose, selfHosted = false }: AdminSidebar
200225
</Toolbar>
201226
<Divider />
202227
<List dense sx={{ pt: 1, flex: 1 }}>
203-
{navItems.map((item) => (
204-
<Box key={item.href}>
205-
<NavLink item={item} active={isActive(item)} />
206-
{item.href === "/admin/services" && selfHosted && (
207-
<Collapse in={servicesExpanded} timeout="auto" unmountOnExit>
208-
<List dense disablePadding>
209-
{SERVICES_SUB_ITEMS.map((sub) => (
210-
<SubNavLink key={sub.href} item={sub} active={isSubActive(sub)} />
211-
))}
212-
</List>
213-
</Collapse>
214-
)}
215-
</Box>
216-
))}
228+
{navItems.map((item) => {
229+
const hasActiveChild =
230+
item.href === "/admin/services" && selfHosted && SERVICES_SUB_ITEMS.some(isSubActive);
231+
return (
232+
<Box key={item.href}>
233+
<NavLink item={item} active={isActive(item)} sectionActive={hasActiveChild} />
234+
{item.href === "/admin/services" && selfHosted && (
235+
<Collapse in={servicesExpanded} timeout="auto" unmountOnExit>
236+
<List dense disablePadding>
237+
{SERVICES_SUB_ITEMS.map((sub) => (
238+
<SubNavLink key={sub.href} item={sub} active={isSubActive(sub)} />
239+
))}
240+
</List>
241+
</Collapse>
242+
)}
243+
</Box>
244+
);
245+
})}
217246
</List>
218247
</>
219248
);

0 commit comments

Comments
 (0)