ajustes no menu

This commit is contained in:
Gabriel Santana de Menezes 2026-05-03 21:47:57 -04:00
parent 734e5d19a7
commit f14742b312

View file

@ -27,11 +27,21 @@ const navLinkClassName = ({ isActive }: { isActive: boolean }) =>
: "text-text-muted hover:bg-surface-muted hover:text-text-main", : "text-text-muted hover:bg-surface-muted hover:text-text-main",
); );
const dropdownItemClassName = ({ isActive }: { isActive: boolean }) =>
cn(
"flex w-full items-center gap-3 rounded-xl px-3 py-2.5 text-sm font-bold transition-all duration-200",
isActive
? "bg-brand/10 text-brand"
: "text-text-muted hover:bg-surface-muted hover:text-text-main"
);
export function AppShell() { export function AppShell() {
const { user, isAuthenticated, isLoading, logout, activeOrg, setActiveOrg } = const { user, isAuthenticated, isLoading, logout, activeOrg, setActiveOrg } =
useAuth(); useAuth();
const [showOrgModal, setShowOrgModal] = useState(false); const [showOrgModal, setShowOrgModal] = useState(false);
const [showOrgSwitcher, setShowOrgSwitcher] = useState(false); const [showOrgSwitcher, setShowOrgSwitcher] = useState(false);
const [showTasksDropdown, setShowTasksDropdown] = useState(false);
const [showOrgDropdown, setShowOrgDropdown] = useState(false);
React.useEffect(() => { React.useEffect(() => {
if (isAuthenticated && user && user.organizations.length === 0) { if (isAuthenticated && user && user.organizations.length === 0) {
@ -170,53 +180,142 @@ export function AppShell() {
</div> </div>
<nav className="hidden items-center gap-1 md:flex"> <nav className="hidden items-center gap-1 md:flex">
<NavLink to="/" end className={navLinkClassName}> {/* Tarefas Dropdown */}
<ListTodo size={18} /> <div className="relative">
Minhas Tarefas <NavLink
</NavLink> to="/"
<NavLink to="/board" className={navLinkClassName}> className={({ isActive }) => {
<Columns size={18} /> const isBoardActive = window.location.pathname === '/board';
Quadro const active = isActive || isBoardActive;
</NavLink> return cn(
"inline-flex items-center gap-2 rounded-xl px-4 py-2 text-sm font-semibold transition-all duration-200",
active || showTasksDropdown
? "bg-brand text-white shadow-md shadow-brand/20"
: "text-text-muted hover:bg-surface-muted hover:text-text-main"
);
}}
onClick={(e) => {
e.preventDefault();
setShowTasksDropdown(!showTasksDropdown);
}}
>
<ListTodo size={18} />
Tarefas
<ChevronDown size={14} className={cn("transition-transform", showTasksDropdown && "rotate-180")} />
</NavLink>
{showTasksDropdown && (
<>
<div
className="fixed inset-0 z-40"
onClick={() => setShowTasksDropdown(false)}
/>
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="absolute left-0 mt-2 z-50 w-48 rounded-2xl border border-border-soft bg-surface p-2 shadow-xl shadow-brand/10"
>
<NavLink
to="/"
end
onClick={() => setShowTasksDropdown(false)}
className={dropdownItemClassName}
>
<ListTodo size={18} />
Minhas Tarefas
</NavLink>
<NavLink
to="/board"
onClick={() => setShowTasksDropdown(false)}
className={(props) => cn(dropdownItemClassName(props), "mt-1")}
>
<Columns size={18} />
Quadro
</NavLink>
</motion.div>
</>
)}
</div>
<NavLink to="/projects" className={navLinkClassName}> <NavLink to="/projects" className={navLinkClassName}>
<FolderKanban size={18} /> <FolderKanban size={18} />
Projetos Projetos
</NavLink> </NavLink>
<NavLink to="/requests" className={navLinkClassName}>
<Clock size={18} /> {/* Organizações Dropdown */}
Solicitações <div className="relative">
</NavLink> <NavLink
<NavLink to="/new" className={navLinkClassName}> to="/organizations"
<PlusCircle size={18} /> className={({ isActive }) => {
Nova Tarefa const isRequestsActive = window.location.pathname === '/requests';
</NavLink> const isAdminActive = window.location.pathname === '/admin';
<NavLink to="/organizations" className={navLinkClassName}> const active = isActive || isRequestsActive || isAdminActive;
<Building2 size={18} /> return cn(
Organizações "inline-flex items-center gap-2 rounded-xl px-4 py-2 text-sm font-semibold transition-all duration-200",
</NavLink> active || showOrgDropdown
{user?.organizations.some( ? "bg-brand text-white shadow-md shadow-brand/20"
(org) => : "text-text-muted hover:bg-surface-muted hover:text-text-main"
org.roles.includes("OWNER") || org.roles.includes("ADMIN"), );
) && ( }}
<NavLink to="/admin" className={navLinkClassName}> onClick={(e) => {
<Settings size={18} /> e.preventDefault();
Gestão setShowOrgDropdown(!showOrgDropdown);
}}
>
<Building2 size={18} />
Organizações
<ChevronDown size={14} className={cn("transition-transform", showOrgDropdown && "rotate-180")} />
</NavLink> </NavLink>
)}
{showOrgDropdown && (
<>
<div
className="fixed inset-0 z-40"
onClick={() => setShowOrgDropdown(false)}
/>
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="absolute right-0 mt-2 z-50 w-56 rounded-2xl border border-border-soft bg-surface p-2 shadow-xl shadow-brand/10"
>
<NavLink
to="/organizations"
onClick={() => setShowOrgDropdown(false)}
className={dropdownItemClassName}
>
<Building2 size={18} />
Minhas Organizações
</NavLink>
<NavLink
to="/requests"
onClick={() => setShowOrgDropdown(false)}
className={(props) => cn(dropdownItemClassName(props), "mt-1")}
>
<Clock size={18} />
Solicitações
</NavLink>
{user?.organizations.some(
(org) => org.roles.includes("OWNER") || org.roles.includes("ADMIN")
) && (
<NavLink
to="/admin"
onClick={() => setShowOrgDropdown(false)}
className={(props) => cn(dropdownItemClassName(props), "mt-1")}
>
<Settings size={18} />
Gestão da Org
</NavLink>
)}
</motion.div>
</>
)}
</div>
</nav> </nav>
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="hidden h-8 w-px bg-border-soft md:block" /> <div className="hidden h-8 w-px bg-border-soft md:block" />
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<img
src={user?.photo}
alt={user?.name}
className="h-8 w-8 rounded-full border border-accent/20 object-cover"
/>
<span className="hidden text-sm font-medium text-text-muted lg:block">
{user?.name}
</span>
<button <button
onClick={logout} onClick={logout}
className="ml-2 p-2 text-text-muted hover:text-danger transition-colors" className="ml-2 p-2 text-text-muted hover:text-danger transition-colors"
@ -239,38 +338,118 @@ export function AppShell() {
{/* Footer / Mobile Nav */} {/* Footer / Mobile Nav */}
<footer className="border-t border-border-soft bg-surface py-6 md:hidden"> <footer className="border-t border-border-soft bg-surface py-6 md:hidden">
<nav className="flex justify-around px-4"> <nav className="flex justify-around px-4">
<NavLink to="/" end className={navLinkClassName}> {/* Mobile Tarefas Group */}
<ListTodo size={18} /> <div className="relative">
Tarefas <button
</NavLink> onClick={() => setShowTasksDropdown(!showTasksDropdown)}
<NavLink to="/board" className={navLinkClassName}> className={cn(
<Columns size={18} /> navLinkClassName({
Quadro isActive: window.location.pathname === '/' || window.location.pathname === '/board'
</NavLink> }),
"flex-col gap-0.5 py-1"
)}
>
<ListTodo size={20} />
<span className="text-[10px]">Tarefas</span>
</button>
{showTasksDropdown && (
<>
<div
className="fixed inset-0 z-40"
onClick={() => setShowTasksDropdown(false)}
/>
<motion.div
initial={{ opacity: 0, y: -10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
className="absolute bottom-full left-1/2 -translate-x-1/2 mb-4 z-50 w-40 rounded-2xl border border-border-soft bg-surface p-1 shadow-2xl"
>
<NavLink
to="/"
end
onClick={() => setShowTasksDropdown(false)}
className={dropdownItemClassName}
>
<ListTodo size={18} />
Lista
</NavLink>
<NavLink
to="/board"
onClick={() => setShowTasksDropdown(false)}
className={(props) => cn(dropdownItemClassName(props), "mt-1")}
>
<Columns size={18} />
Quadro
</NavLink>
</motion.div>
</>
)}
</div>
<NavLink to="/projects" className={navLinkClassName}> <NavLink to="/projects" className={navLinkClassName}>
<FolderKanban size={18} /> <FolderKanban size={18} />
Projetos Projetos
</NavLink> </NavLink>
<NavLink to="/requests" className={navLinkClassName}>
<Clock size={18} /> {/* Mobile Organizações Group */}
Pedidos <div className="relative">
</NavLink> <button
<NavLink to="/new" className={navLinkClassName}> onClick={() => setShowOrgDropdown(!showOrgDropdown)}
<PlusCircle size={18} /> className={cn(
Criar navLinkClassName({
</NavLink> isActive: window.location.pathname === '/organizations' ||
<NavLink to="/organizations" className={navLinkClassName}> window.location.pathname === '/requests' ||
<Building2 size={18} /> window.location.pathname === '/admin'
Org }),
</NavLink> "flex-col gap-0.5 py-1"
{user?.organizations.some( )}
(org) => org.roles.includes("OWNER") || org.roles.includes("ADMIN"), >
) && ( <Building2 size={20} />
<NavLink to="/admin" className={navLinkClassName}> <span className="text-[10px]">Org</span>
<Settings size={18} /> </button>
Gestão
</NavLink> {showOrgDropdown && (
)} <>
<div
className="fixed inset-0 z-40"
onClick={() => setShowOrgDropdown(false)}
/>
<motion.div
initial={{ opacity: 0, y: -10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
className="absolute bottom-full left-1/2 -translate-x-1/2 mb-4 z-50 w-48 rounded-2xl border border-border-soft bg-surface p-1 shadow-2xl"
>
<NavLink
to="/organizations"
onClick={() => setShowOrgDropdown(false)}
className={dropdownItemClassName}
>
<Building2 size={18} />
Minhas Orgs
</NavLink>
<NavLink
to="/requests"
onClick={() => setShowOrgDropdown(false)}
className={(props) => cn(dropdownItemClassName(props), "mt-1")}
>
<Clock size={18} />
Pedidos
</NavLink>
{user?.organizations.some(
(org) => org.roles.includes("OWNER") || org.roles.includes("ADMIN")
) && (
<NavLink
to="/admin"
onClick={() => setShowOrgDropdown(false)}
className={(props) => cn(dropdownItemClassName(props), "mt-1")}
>
<Settings size={18} />
Gestão
</NavLink>
)}
</motion.div>
</>
)}
</div>
</nav> </nav>
</footer> </footer>
<OnboardingModal <OnboardingModal