Merge pull request #63 from fsolla/cursor/remove-bottom-nav-mobile-a78d
B73 — Remover bottom navigation bar no mobile
This commit is contained in:
commit
b0734ccd17
5 changed files with 6 additions and 78 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Remover bottom navigation bar no mobile
|
||||
|
||||
Status: rascunho
|
||||
Status: entregue (2026-07-30)
|
||||
Atualizado em: 2026-07-29
|
||||
Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B — **B73**; chassis UX-1)
|
||||
Impeccable: B — encaixe no shell `(app)`; remove chrome, não cria rota nova
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {
|
|||
BiometricEnrollmentToast,
|
||||
type BiometricEnrollmentOffer,
|
||||
} from '@/components/campaign/shell/BiometricEnrollmentToast'
|
||||
import { CampaignBottomNav } from '@/components/campaign/shell/CampaignBottomNav'
|
||||
import { CampaignMobileTopBar } from '@/components/campaign/shell/CampaignMobileTopBar'
|
||||
import { CampaignSidebar } from '@/components/campaign/shell/CampaignSidebar'
|
||||
import { CampaignSidebarViewportDefault } from '@/components/campaign/shell/CampaignSidebarViewportDefault'
|
||||
|
|
@ -78,11 +77,10 @@ export default async function CampaignAppLayout({ children }: { children: React.
|
|||
</header>
|
||||
<div
|
||||
data-slot="campaign-content-scroll"
|
||||
className="min-h-0 flex-1 overflow-y-auto overscroll-contain p-4 pb-24 md:p-6 md:pb-6 print:h-auto print:overflow-visible print:p-0"
|
||||
className="min-h-0 flex-1 overflow-y-auto overscroll-contain p-4 md:p-6 print:h-auto print:overflow-visible print:p-0"
|
||||
>
|
||||
<TooltipProvider delayDuration={300}>{children}</TooltipProvider>
|
||||
</div>
|
||||
<CampaignBottomNav role={user.role} />
|
||||
<Toaster position="top-center" />
|
||||
<InstallPwaToast />
|
||||
{biometricEnrollment ? <BiometricEnrollmentToast {...biometricEnrollment} /> : null}
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
import { getCampaignBottomNav, isCampaignNavActive } from '@/components/campaign/shell/nav'
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { CampaignUser } from '@/payload-types'
|
||||
|
||||
export const CampaignBottomNav = ({ role }: { role: CampaignUser['role'] }) => {
|
||||
const pathname = usePathname()
|
||||
const navItems = getCampaignBottomNav(role)
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-label="Navegação principal"
|
||||
className="fixed inset-x-0 bottom-0 border-t bg-background pb-[env(safe-area-inset-bottom)] md:hidden print:hidden"
|
||||
>
|
||||
<ul
|
||||
className="m-0 grid list-none p-0"
|
||||
style={{ gridTemplateColumns: `repeat(${navItems.length}, minmax(0, 1fr))` }}
|
||||
>
|
||||
{navItems.map((item) => {
|
||||
const active = isCampaignNavActive(pathname, item.href)
|
||||
|
||||
return (
|
||||
<li key={item.href} className="m-0 p-0">
|
||||
<Link
|
||||
href={item.href}
|
||||
aria-current={active ? 'page' : undefined}
|
||||
className={cn(
|
||||
'flex min-h-12 flex-col items-center justify-center gap-0.5 px-3 py-1.5 text-xs font-medium text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
||||
active && 'text-primary',
|
||||
)}
|
||||
>
|
||||
<item.icon aria-hidden="true" />
|
||||
<span>{item.title}</span>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ const staffNav: CampaignNavItem[] = [
|
|||
|
||||
/**
|
||||
* Reference material, not a place to work: sits in its own group at the foot
|
||||
* of the sidebar, below the destinations, and never in the mobile bottom bar.
|
||||
* of the sidebar, below the destinations.
|
||||
* Staff-only — every documented number is one a `leader` never sees.
|
||||
*
|
||||
* The href is a literal, not an import from `campaignIntelligenceConcepts.ts`:
|
||||
|
|
@ -76,25 +76,6 @@ export const getCampaignNav = (role: CampaignUser['role']): CampaignNavItem[] =>
|
|||
export const getCampaignSecondaryNav = (role: CampaignUser['role']): CampaignNavItem[] =>
|
||||
isStaffCampaignRole(role) ? staffSecondaryNav : []
|
||||
|
||||
/**
|
||||
* Compact set for the mobile bottom bar (max 5 items with a home slot).
|
||||
* Assessores stays sidebar-only (same as perfil/organizações).
|
||||
*/
|
||||
export const getCampaignBottomNav = (role: CampaignUser['role']): CampaignNavItem[] => {
|
||||
const nav = getCampaignNav(role)
|
||||
if (role === 'leader') return nav
|
||||
|
||||
return nav
|
||||
.filter(
|
||||
(item) =>
|
||||
item.href !== '/campanha/quadro' &&
|
||||
item.href !== '/campanha/territorios' &&
|
||||
item.href !== '/campanha/apoiadores' &&
|
||||
item.href !== '/campanha/assessores',
|
||||
)
|
||||
.slice(0, 5)
|
||||
}
|
||||
|
||||
/** Home matches only exactly; other items also match nested paths. */
|
||||
export const isCampaignNavActive = (pathname: string, href: string): boolean => {
|
||||
if (href === '/campanha') {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,7 @@
|
|||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
getCampaignBottomNav,
|
||||
getCampaignNav,
|
||||
getCampaignSecondaryNav,
|
||||
} from '@/components/campaign/shell/nav'
|
||||
import { getCampaignNav, getCampaignSecondaryNav } from '@/components/campaign/shell/nav'
|
||||
import {
|
||||
CAMPAIGN_CONCEPT_CATEGORIES,
|
||||
CAMPAIGN_CONCEPTS_PATH,
|
||||
|
|
@ -78,10 +74,8 @@ describe('concepts sidebar entry', () => {
|
|||
expect(getCampaignSecondaryNav('leader')).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('stays out of the work destinations and the mobile bottom bar', () => {
|
||||
const hrefs = [...getCampaignNav('coordinator'), ...getCampaignBottomNav('coordinator')].map(
|
||||
(item) => item.href,
|
||||
)
|
||||
it('stays out of the work destinations in the sidebar', () => {
|
||||
const hrefs = getCampaignNav('coordinator').map((item) => item.href)
|
||||
|
||||
expect(hrefs).not.toContain(CAMPAIGN_CONCEPTS_PATH)
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue