fix(admin): auto-expand sidebar navigation group for active child page
- Add getExpandedMenusForPath to auto-expand the parent menu group when navigating to a child page (e.g., /admin/users expands "系统管理") - Add hasActiveChild highlight on parent menu group button (bg-gray-100) - Use lazy initialization for expandedMenus state based on current path - Use useEffect to track pathname changes and auto-expand accordingly - Replace `path` unused param with `_path` to satisfy TypeScript strict
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { useAuth } from './auth-context';
|
||||
@@ -82,11 +82,48 @@ const menuItems = [
|
||||
|
||||
export function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
const [expandedMenus, setExpandedMenus] = useState<Set<string>>(new Set(['内容管理']));
|
||||
const { user, logout } = useAuth();
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
|
||||
const isActive = (href: string) => pathname === href || pathname?.startsWith(href + '/');
|
||||
|
||||
/**
|
||||
* 根据当前路径自动展开对应的父菜单组
|
||||
*/
|
||||
const getExpandedMenusForPath = (_path: string): Set<string> => {
|
||||
const result = new Set<string>();
|
||||
for (const group of menuItems) {
|
||||
for (const item of group.children) {
|
||||
if (isActive(item.href)) {
|
||||
result.add(group.label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 若当前路径在某个组内,保留已有展开状态并追加;否则保留默认展开
|
||||
if (result.size > 0) {
|
||||
return result;
|
||||
}
|
||||
return new Set(['内容管理']);
|
||||
};
|
||||
|
||||
const [expandedMenus, setExpandedMenus] = useState<Set<string>>(() => getExpandedMenusForPath(pathname));
|
||||
|
||||
// 路径变化时自动展开对应父菜单组
|
||||
const prevPathname = useRef(pathname);
|
||||
useEffect(() => {
|
||||
if (prevPathname.current !== pathname) {
|
||||
prevPathname.current = pathname;
|
||||
const menusForPath = getExpandedMenusForPath(pathname);
|
||||
setExpandedMenus((prev) => {
|
||||
const next = new Set(prev);
|
||||
menusForPath.forEach((label) => next.add(label));
|
||||
return next;
|
||||
});
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
const toggleMenu = (label: string) => {
|
||||
setExpandedMenus((prev) => {
|
||||
const next = new Set(prev);
|
||||
@@ -101,8 +138,6 @@ export function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
router.push('/admin/login');
|
||||
};
|
||||
|
||||
const isActive = (href: string) => pathname === href || pathname?.startsWith(href + '/');
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Mobile overlay */}
|
||||
@@ -146,11 +181,17 @@ export function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
</Link>
|
||||
|
||||
{/* Menu groups */}
|
||||
{menuItems.map((group) => (
|
||||
{menuItems.map((group) => {
|
||||
const hasActiveChild = group.children.some((item) => isActive(item.href));
|
||||
return (
|
||||
<div key={group.label}>
|
||||
<button
|
||||
onClick={() => toggleMenu(group.label)}
|
||||
className="flex items-center justify-between w-full px-3 py-2.5 rounded-lg text-sm font-medium text-gray-600 hover:bg-gray-100 transition-colors"
|
||||
className={`flex items-center justify-between w-full px-3 py-2.5 rounded-lg text-sm font-medium transition-colors ${
|
||||
hasActiveChild
|
||||
? 'bg-gray-100 text-gray-900'
|
||||
: 'text-gray-600 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
<span className="flex items-center gap-3">
|
||||
<group.icon className="w-4 h-4" />
|
||||
@@ -182,7 +223,8 @@ export function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
{/* User info */}
|
||||
|
||||
Reference in New Issue
Block a user