Try to fix submenu postition
Signed-off-by: Rodrigo Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
c459997cd9
commit
5559eb98b8
1 file changed
+93
-36
@@ -1,4 +1,4 @@
|
||||
import React, { useState, Fragment, useEffect } from "react";
|
||||
import React, { useState, Fragment, useEffect, useRef } from "react";
|
||||
import { Outlet, Link, useLocation } from "react-router-dom";
|
||||
import { useAuth } from "../../contexts/AuthContext";
|
||||
import {
|
||||
@@ -34,6 +34,8 @@ export const MainLayout: React.FC = () => {
|
||||
const { user, signOut } = useAuth();
|
||||
const [userProfile, setUserProfile] = useState<any>(null);
|
||||
const { isDarkMode, toggleDarkMode } = useTheme();
|
||||
const [activeSubmenu, setActiveSubmenu] = useState<string | null>(null);
|
||||
const submenuTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// Adicionar efeito para buscar perfil do usuário
|
||||
useEffect(() => {
|
||||
@@ -114,6 +116,46 @@ export const MainLayout: React.FC = () => {
|
||||
return location.pathname.startsWith(path);
|
||||
};
|
||||
|
||||
// Função para lidar com hover no menu
|
||||
const handleMenuMouseEnter = (menuLabel: string) => {
|
||||
if (submenuTimeoutRef.current) {
|
||||
clearTimeout(submenuTimeoutRef.current);
|
||||
submenuTimeoutRef.current = null;
|
||||
}
|
||||
setActiveSubmenu(menuLabel);
|
||||
|
||||
// Atualiza a posição vertical do submenu
|
||||
const menuItem = document.querySelector(`[data-menu-label="${menuLabel}"]`);
|
||||
if (menuItem) {
|
||||
const rect = menuItem.getBoundingClientRect();
|
||||
document.documentElement.style.setProperty('--menu-item-top', `${rect.top}px`);
|
||||
}
|
||||
};
|
||||
|
||||
// Função para lidar com mouseleave do menu
|
||||
const handleMenuMouseLeave = () => {
|
||||
submenuTimeoutRef.current = setTimeout(() => {
|
||||
setActiveSubmenu(null);
|
||||
}, 300); // Atraso de 300ms antes de fechar o submenu
|
||||
};
|
||||
|
||||
// Função para lidar com mouseenter no submenu
|
||||
const handleSubmenuMouseEnter = () => {
|
||||
if (submenuTimeoutRef.current) {
|
||||
clearTimeout(submenuTimeoutRef.current);
|
||||
submenuTimeoutRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Limpar timeout quando o componente é desmontado
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (submenuTimeoutRef.current) {
|
||||
clearTimeout(submenuTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-gray-100 dark:bg-gray-900">
|
||||
{/* Sidebar com barra de rolagem */}
|
||||
@@ -127,7 +169,10 @@ export const MainLayout: React.FC = () => {
|
||||
<nav className="flex-1 overflow-y-auto">
|
||||
<div className="py-4">
|
||||
{menuItems.map((item, index) => (
|
||||
<div key={item.path || item.label} className="px-2 mb-2">
|
||||
<div
|
||||
key={item.path || item.label}
|
||||
className="px-2 mb-2"
|
||||
>
|
||||
{!item.subitems ? (
|
||||
<Link
|
||||
to={item.path}
|
||||
@@ -142,7 +187,12 @@ export const MainLayout: React.FC = () => {
|
||||
<span className="text-xs mt-1 text-white/80">{item.label}</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="relative group">
|
||||
<div
|
||||
className="relative"
|
||||
data-menu-label={item.label}
|
||||
onMouseEnter={() => handleMenuMouseEnter(item.label)}
|
||||
onMouseLeave={handleMenuMouseLeave}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col items-center justify-center p-3 rounded-lg transition-colors hover:bg-white/10 cursor-pointer ${
|
||||
item.subitems.some(subitem => isCurrentPath(subitem.path))
|
||||
@@ -154,45 +204,52 @@ export const MainLayout: React.FC = () => {
|
||||
<item.icon className="h-6 w-6 text-white opacity-80" />
|
||||
<span className="text-xs mt-1 text-white/80">{item.label}</span>
|
||||
</div>
|
||||
|
||||
{/* Submenu corrigido - posicionado fora da sidebar como pop-up */}
|
||||
<div
|
||||
className="fixed left-20 z-50"
|
||||
style={{
|
||||
top: 'var(--submenu-top)',
|
||||
'--submenu-top': `${index * 70 + 100}px`
|
||||
} as React.CSSProperties}
|
||||
>
|
||||
<div className="opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200">
|
||||
<div className="bg-blue-800/95 backdrop-blur-sm rounded-lg py-2 px-1 shadow-xl w-[140px] border border-blue-700/30">
|
||||
{item.subitems
|
||||
.filter(subitem =>
|
||||
!subitem.roles?.length ||
|
||||
(userProfile?.perfil && subitem.roles.includes(userProfile.perfil))
|
||||
)
|
||||
.map((subitem) => (
|
||||
<Link
|
||||
key={subitem.path}
|
||||
to={subitem.path}
|
||||
className={`block px-3 py-2 hover:bg-blue-700/50 rounded-lg transition-colors ${
|
||||
isCurrentPath(subitem.path) ? "bg-blue-700/70" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<subitem.icon className="h-5 w-5 text-white opacity-80" />
|
||||
<span className="text-sm text-white/90">{subitem.label}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Submenus renderizados fora da estrutura do menu principal */}
|
||||
{menuItems
|
||||
.filter(item => item.subitems)
|
||||
.map(item => (
|
||||
<div
|
||||
key={`submenu-${item.label}`}
|
||||
className={`fixed left-20 z-50 ${activeSubmenu === item.label ? 'block' : 'hidden'}`}
|
||||
style={{ top: 'var(--menu-item-top, 0)' }}
|
||||
onMouseEnter={handleSubmenuMouseEnter}
|
||||
onMouseLeave={handleMenuMouseLeave}
|
||||
>
|
||||
<div
|
||||
className="transition-all duration-200 ml-2"
|
||||
style={{ transformOrigin: 'left center' }}
|
||||
>
|
||||
<div className="bg-blue-800/95 backdrop-blur-sm rounded-lg py-2 px-1 shadow-xl w-[140px] border border-blue-700/30">
|
||||
{item.subitems
|
||||
.filter(subitem =>
|
||||
!subitem.roles?.length ||
|
||||
(userProfile?.perfil && subitem.roles.includes(userProfile.perfil))
|
||||
)
|
||||
.map((subitem) => (
|
||||
<Link
|
||||
key={subitem.path}
|
||||
to={subitem.path}
|
||||
className={`block px-3 py-2 hover:bg-blue-700/50 rounded-lg transition-colors ${
|
||||
isCurrentPath(subitem.path) ? "bg-blue-700/70" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<subitem.icon className="h-5 w-5 text-white opacity-80" />
|
||||
<span className="text-sm text-white/90">{subitem.label}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
|
||||
Reference in new issue
Block a user