Add active state highlighting to user menu
- Highlight user menu trigger when on pages accessible from dropdown (admin/*, settings, api-keys) - Add .active styling for dropdown menu items (current page) - Use NavLink end prop on /admin to prevent false positive matches - Support auto accent color overrides for light backgrounds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import { NavLink, useNavigate } from 'react-router-dom';
|
import { NavLink, useNavigate, useLocation } from 'react-router-dom';
|
||||||
import { useAuth } from '../contexts/AuthContext';
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
import { useTranslation } from '../contexts/LanguageContext';
|
import { useTranslation } from '../contexts/LanguageContext';
|
||||||
import { useTheme } from '../contexts/ThemeContext';
|
import { useTheme } from '../contexts/ThemeContext';
|
||||||
@@ -12,9 +12,15 @@ export default function UserMenu({ onOpenChange }: { onOpenChange?: (isOpen: boo
|
|||||||
const { theme, toggleTheme, darkModeLocation, languageLocation, showDarkModeToggle, showLanguageToggle, hasInitializedSettings: themeInitialized } = useTheme();
|
const { theme, toggleTheme, darkModeLocation, languageLocation, showDarkModeToggle, showLanguageToggle, hasInitializedSettings: themeInitialized } = useTheme();
|
||||||
const { isCollapsed, isMobileOpen, closeMobileMenu, sidebarMode } = useSidebar();
|
const { isCollapsed, isMobileOpen, closeMobileMenu, sidebarMode } = useSidebar();
|
||||||
const { viewMode } = useViewMode();
|
const { viewMode } = useViewMode();
|
||||||
|
const location = useLocation();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const menuRef = useRef<HTMLDivElement>(null);
|
const menuRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// Check if we're on an admin page or settings page (pages accessible from this menu)
|
||||||
|
const isMenuPageActive = location.pathname.startsWith('/admin') ||
|
||||||
|
location.pathname === '/settings' ||
|
||||||
|
location.pathname === '/api-keys';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onOpenChange?.(isOpen);
|
onOpenChange?.(isOpen);
|
||||||
}, [isOpen, onOpenChange]);
|
}, [isOpen, onOpenChange]);
|
||||||
@@ -68,6 +74,7 @@ export default function UserMenu({ onOpenChange }: { onOpenChange?: (isOpen: boo
|
|||||||
<nav className="user-menu-nav">
|
<nav className="user-menu-nav">
|
||||||
<NavLink
|
<NavLink
|
||||||
to="/admin"
|
to="/admin"
|
||||||
|
end
|
||||||
className="user-menu-item"
|
className="user-menu-item"
|
||||||
onClick={(e) => handleNavClick(e, '/admin')}
|
onClick={(e) => handleNavClick(e, '/admin')}
|
||||||
>
|
>
|
||||||
@@ -162,7 +169,7 @@ export default function UserMenu({ onOpenChange }: { onOpenChange?: (isOpen: boo
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className={`user-menu-trigger ${isOpen ? 'active' : ''}`}
|
className={`user-menu-trigger ${isOpen ? 'active' : ''} ${isMenuPageActive ? 'admin-active' : ''}`}
|
||||||
onClick={toggleMenu}
|
onClick={toggleMenu}
|
||||||
title={t.dashboard.profile}
|
title={t.dashboard.profile}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -797,12 +797,25 @@ button.nav-item {
|
|||||||
background: rgba(var(--color-accent-rgb), 0.10);
|
background: rgba(var(--color-accent-rgb), 0.10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Admin page active state - same style as nav-item.active */
|
||||||
|
.user-menu-trigger.admin-active {
|
||||||
|
background: rgba(var(--color-accent-rgb), 0.12);
|
||||||
|
border: 1px solid rgba(var(--color-accent-rgb), 0.18);
|
||||||
|
box-shadow: 0 2px 8px rgba(var(--color-accent-rgb), 0.15);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.sidebar.dynamic.collapsed .user-menu-trigger:hover,
|
.sidebar.dynamic.collapsed .user-menu-trigger:hover,
|
||||||
.sidebar.dynamic.collapsed .user-menu-trigger.active {
|
.sidebar.dynamic.collapsed .user-menu-trigger.active {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
/* Let the inner user-info-compact handle hover */
|
/* Let the inner user-info-compact handle hover */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar.dynamic.collapsed .user-menu-trigger.admin-active {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.user-menu-trigger .user-info-compact {
|
.user-menu-trigger .user-info-compact {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
/* Override default */
|
/* Override default */
|
||||||
@@ -1035,6 +1048,27 @@ button.nav-item {
|
|||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Active menu item (current page) */
|
||||||
|
.user-menu-item.active {
|
||||||
|
background: rgba(var(--color-accent-rgb), 0.12);
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu-item.active .material-symbols-outlined {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auto accent override for active menu item */
|
||||||
|
[data-accent='auto'] .user-menu-item.active {
|
||||||
|
background: #f3f4f6;
|
||||||
|
color: #111827;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-accent='auto'] .user-menu-item.active .material-symbols-outlined {
|
||||||
|
color: #111827;
|
||||||
|
}
|
||||||
|
|
||||||
/* Danger item (logout) */
|
/* Danger item (logout) */
|
||||||
.user-menu-item.danger {
|
.user-menu-item.danger {
|
||||||
color: var(--color-error);
|
color: var(--color-error);
|
||||||
@@ -1126,6 +1160,27 @@ button.nav-item {
|
|||||||
background: rgba(229, 231, 235, 0.15);
|
background: rgba(229, 231, 235, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* User menu trigger on admin pages with auto accent */
|
||||||
|
[data-accent='auto'] .user-menu-trigger.admin-active {
|
||||||
|
background: #f3f4f6;
|
||||||
|
box-shadow: 0 0 16px 2px rgba(243, 244, 246, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-accent='auto'] .user-menu-trigger.admin-active .user-initial {
|
||||||
|
background: #111827;
|
||||||
|
color: #f3f4f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-accent='auto'] .user-menu-trigger.admin-active .user-name,
|
||||||
|
[data-accent='auto'] .user-menu-trigger.admin-active .chevron {
|
||||||
|
color: #111827 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[data-accent='auto'] .user-menu-trigger.admin-active:hover {
|
||||||
|
background: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
/* View mode toggle with auto accent */
|
/* View mode toggle with auto accent */
|
||||||
[data-accent='auto'] .view-mode-toggle:hover {
|
[data-accent='auto'] .view-mode-toggle:hover {
|
||||||
background: rgba(229, 231, 235, 0.12);
|
background: rgba(229, 231, 235, 0.12);
|
||||||
|
|||||||
Reference in New Issue
Block a user