Skip to main content
Glama
MobileNavbar.tsx7.07 kB
'use client'; import { m, type Variants } from 'framer-motion'; import { type ReactElement, type ReactNode, useRef, useState } from 'react'; import { useScrollBlockage, useScrollDetection } from '../../hooks'; import { cn } from '../../utils/cn'; import { MaxHeightSmoother } from '../MaxHeightSmoother'; import type { TabSelectorItemProps } from '../TabSelector'; import { Burger } from './Burger'; /** * Props for the MobileNavbar component * @template T - The tab props type extending TabProps */ type MobileNavbarProps<T extends TabSelectorItemProps> = { /** Logo component or element displayed in the header */ logo: ReactNode; /** Additional content displayed at the top of expanded mobile menu */ topChildren?: ReactNode; /** Navigation sections displayed in the top area of expanded menu */ topSections?: ReactElement<T>[]; /** Additional content displayed at the bottom of expanded mobile menu */ bottomChildren?: ReactNode; /** Navigation sections displayed in the bottom area of expanded menu */ bottomSections?: ReactElement<T>[]; /** Right-aligned items in the collapsed header (e.g., search, notifications) */ rightItems?: ReactNode; /** Whether the navbar should be rollable (default: true) */ rollable?: boolean; }; /** * Framer Motion animation variants for staggered menu item reveals * Creates a smooth cascading effect when menu opens/closes */ const navVariants: Variants = { open: { transition: { staggerChildren: 0.07, delayChildren: 0.2 }, }, closed: { transition: { staggerChildren: 0.05, staggerDirection: -1 }, }, }; /** * Shared background styling for mobile navbar components * Provides glass-morphism effect with blur and transparency */ const bgStyle = 'bg-card/95 shadow-[0_0_10px_-15px_rgba(0,0,0,0.3)] backdrop-blur'; /** * Mobile Navigation Bar Component * * A sophisticated mobile-first navigation component with rollable full-screen menu, * scroll-aware behavior, and smooth animations. Optimized for touch interactions and * mobile user experience patterns. * * Features: * - rollable hamburger menu with full-screen overlay * - Auto-hide on scroll down, show on scroll up for screen space optimization * - Background scroll prevention when menu is open * - Staggered animations for smooth menu item reveals * - Flexible content areas (top/bottom children and sections) * - Responsive layout with viewport-aware sizing * - Backdrop blur effects for modern glass-morphism design * * Layout Structure: * ``` * [Logo] ----------- [Right Items] [Burger] * (when expanded) * ┌─────────────────────────────────────────┐ * │ [Top Children] │ * │ [Top Sections - Navigation Items] │ * │ [Bottom Sections - Navigation Items] │ * │ [Bottom Children] │ * └─────────────────────────────────────────┘ * ``` * * Behavioral Features: * - Sticky positioning with dynamic hide/show based on scroll direction * - Background scroll locking when menu is expanded * - Click outside to close expanded menu * - Smooth height animations with MaxHeightSmoother * - Intelligent burger button visibility (only shown if sections exist) * * Animation Details: * - Menu items animate in with staggered timing (70ms delay between items) * - Exit animations are reversed with 50ms stagger * - Initial delay of 200ms before items start animating in * - Full viewport height menu with dynamic height calculation * * @example * Basic mobile navbar: * ```tsx * <MobileNavbar * logo={<MobileLogo />} * topSections={primaryNavItems} * rightItems={<SearchIcon />} * /> * ``` * * @example * Full-featured mobile navbar: * ```tsx * <MobileNavbar * logo={<Logo />} * topChildren={<WelcomeMessage />} * topSections={mainNavItems} * bottomSections={utilityNavItems} * bottomChildren={<UserProfile />} * rightItems={ * <> * <NotificationIcon /> * <SearchIcon /> * </> * } * /> * ``` * * Accessibility Features: * - Menu expanded state communicated via aria-expanded * - Focus management and keyboard navigation support * - Screen reader friendly with semantic nav structure * * @template T - Tab properties type extending TabProps for type safety * @param props - MobileNavbar component props * @returns Mobile navigation with rollable full-screen menu */ export const MobileNavbar = <T extends TabSelectorItemProps>({ logo, topChildren, topSections = [], bottomChildren, bottomSections = [], rightItems, rollable = true, }: MobileNavbarProps<T>) => { const [isHidden, setIsHidden] = useState<boolean>(false); const [isUnrolled, setIsUnrolled] = useState<boolean>(false); const navRef = useRef<HTMLDivElement>(null); useScrollBlockage({ disableScroll: rollable, key: 'mobile_nav', }); useScrollDetection({ onScrollUp: () => setIsHidden(false), onScrollDown: () => setIsHidden(true), isEnabled: !isUnrolled && rollable, }); const backDivHeight = !isHidden ? (navRef.current?.clientHeight ?? 0) : 0; const isBurgerShowed = topSections.length + bottomSections.length > 0; return ( <nav className={cn( bgStyle, 'sticky top-0 z-50 flex w-screen flex-col transition', isHidden ? '-translate-y-full' : 'translate-y-0' )} id="mobile-menu" > <div className="flex w-full items-center justify-between gap-1 px-4 py-3 md:gap-[10vw]" ref={navRef} > {logo} <div className="flex w-full flex-1 items-center justify-end gap-6"> <div className="flex w-full items-center justify-end gap-1"> {rightItems} </div> {isBurgerShowed && ( <Burger isActive={isUnrolled} onClick={() => setIsUnrolled((isUnrolled) => !isUnrolled)} /> )} </div> </div> <div className={cn( bgStyle, 'absolute bottom-0 left-0 w-full translate-y-full' )} > <MaxHeightSmoother isHidden={!isUnrolled}> <m.div className="flex w-full flex-col pt-10 pb-[20%] text-lg text-text tracking-wide" onClick={() => setIsUnrolled(false)} animate={isUnrolled ? 'open' : 'closed'} variants={navVariants} style={{ height: `calc(100vh - ${backDivHeight}px)`, }} > {topChildren} <div className="flex h-full flex-col justify-center"> {topSections} {bottomSections} </div> <div className="m-auto flex w-full max-w-[400px] items-center justify-center gap-1 px-5 py-3"> {bottomChildren} </div> </m.div> </MaxHeightSmoother> </div> </nav> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server