fix(nav): replace NavigationMenu submenus with DropdownMenu
The Radix NavigationMenu uses a single shared viewport centered under the full nav list. Opening a right-side submenu (Analyzer, Admin) positioned the dropdown panel far to the left, so moving the mouse to reach it crossed other triggers and closed it mid-way. Switch all items-with-children to DropdownMenu, which positions each panel directly under its own trigger. Keeps the same visual style (navigationMenuTriggerStyle, ChevronDown, item layout with icon + description) and active-state highlighting. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
370125d249
commit
2d4a546a8f
1 changed files with 56 additions and 51 deletions
|
|
@ -17,16 +17,21 @@ import {
|
||||||
Brain,
|
Brain,
|
||||||
Search,
|
Search,
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
|
ChevronDown,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
NavigationMenu,
|
NavigationMenu,
|
||||||
NavigationMenuContent,
|
|
||||||
NavigationMenuItem,
|
NavigationMenuItem,
|
||||||
NavigationMenuLink,
|
NavigationMenuLink,
|
||||||
NavigationMenuList,
|
NavigationMenuList,
|
||||||
NavigationMenuTrigger,
|
|
||||||
navigationMenuTriggerStyle,
|
navigationMenuTriggerStyle,
|
||||||
} from '@/components/ui/navigation-menu';
|
} from '@/components/ui/navigation-menu';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ThemeToggle } from '@/components/theme-toggle';
|
import { ThemeToggle } from '@/components/theme-toggle';
|
||||||
import { StatusIndicator } from '@/components/navigation/status-indicator';
|
import { StatusIndicator } from '@/components/navigation/status-indicator';
|
||||||
|
|
@ -242,57 +247,57 @@ export function AppNavigation() {
|
||||||
return (
|
return (
|
||||||
<NavigationMenuItem key={item.title}>
|
<NavigationMenuItem key={item.title}>
|
||||||
{item.children ? (
|
{item.children ? (
|
||||||
<>
|
<DropdownMenu>
|
||||||
<NavigationMenuTrigger
|
<DropdownMenuTrigger asChild>
|
||||||
className={cn(
|
<button
|
||||||
'h-9 px-4 py-2',
|
className={cn(
|
||||||
childActive && cn(activeRule, 'text-foreground'),
|
navigationMenuTriggerStyle(),
|
||||||
)}
|
'h-9 px-4 py-2 group',
|
||||||
>
|
childActive && cn(activeRule, 'text-foreground'),
|
||||||
{item.icon && <item.icon className="w-4 h-4 mr-2" />}
|
)}
|
||||||
{item.title}
|
>
|
||||||
</NavigationMenuTrigger>
|
{item.icon && <item.icon className="w-4 h-4 mr-2" />}
|
||||||
<NavigationMenuContent>
|
{item.title}
|
||||||
<ul className="grid gap-1 p-2 min-w-[320px] max-w-[440px]">
|
<ChevronDown className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180" aria-hidden="true" />
|
||||||
{item.children.map((child) => {
|
</button>
|
||||||
const active = isActive(child.href);
|
</DropdownMenuTrigger>
|
||||||
return (
|
<DropdownMenuContent align="start" className="p-2 min-w-[320px] max-w-[440px]">
|
||||||
<li key={child.title}>
|
{item.children.map((child) => {
|
||||||
<NavigationMenuLink asChild>
|
const active = isActive(child.href);
|
||||||
<Link
|
return (
|
||||||
href={child.href || '#'}
|
<DropdownMenuItem key={child.title} asChild className="p-0 focus:bg-transparent">
|
||||||
|
<Link
|
||||||
|
href={child.href || '#'}
|
||||||
|
className={cn(
|
||||||
|
'flex w-full items-start gap-3 rounded-sm px-3 py-2 text-sm leading-none no-underline outline-none transition-colors cursor-pointer',
|
||||||
|
'hover:bg-accent/40 focus:bg-accent/40',
|
||||||
|
active && 'bg-primary/10 text-primary',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{child.icon && (
|
||||||
|
<child.icon
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-start gap-3 rounded-sm px-3 py-2 leading-none no-underline outline-none transition-colors',
|
'w-4 h-4 mt-0.5 shrink-0',
|
||||||
'hover:bg-accent/40 focus:bg-accent/40',
|
active ? 'text-primary' : 'text-muted-foreground',
|
||||||
active && 'bg-primary/10 text-primary',
|
|
||||||
)}
|
)}
|
||||||
>
|
/>
|
||||||
{child.icon && (
|
)}
|
||||||
<child.icon
|
<div className="min-w-0 flex-1">
|
||||||
className={cn(
|
<div className={cn('font-medium leading-none', active && 'text-primary')}>
|
||||||
'w-4 h-4 mt-0.5 shrink-0',
|
{child.title}
|
||||||
active ? 'text-primary' : 'text-muted-foreground',
|
</div>
|
||||||
)}
|
{child.description && (
|
||||||
/>
|
<p className="mt-1 line-clamp-2 text-xs leading-snug text-muted-foreground">
|
||||||
)}
|
{child.description}
|
||||||
<div className="min-w-0 flex-1">
|
</p>
|
||||||
<div className={cn('text-sm font-medium leading-none', active && 'text-primary')}>
|
)}
|
||||||
{child.title}
|
</div>
|
||||||
</div>
|
</Link>
|
||||||
{child.description && (
|
</DropdownMenuItem>
|
||||||
<p className="mt-1 line-clamp-2 text-xs leading-snug text-muted-foreground">
|
);
|
||||||
{child.description}
|
})}
|
||||||
</p>
|
</DropdownMenuContent>
|
||||||
)}
|
</DropdownMenu>
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
</NavigationMenuLink>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</NavigationMenuContent>
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<Link href={item.href || '#'} legacyBehavior passHref>
|
<Link href={item.href || '#'} legacyBehavior passHref>
|
||||||
<NavigationMenuLink
|
<NavigationMenuLink
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue