cover

Esta es la <navbar> que está de moda


En este video, vamos a animar una barra de navegación, para que se sienta todavía mejor. 👨🏻‍💻

Primera parte: Maquetado

<AnimatedNavBar> será nuestro componente principal, pero se armará de otros cuatro, tres visibles y un <Button> por debajo.

// app/components/AnimatedNavBar.tsx export const AnimatedNavBar = () => { return ( <nav className="px-4 mx-auto max-w-5xl flex justify-around items-center h-14 bg-white"> <Logo /> <Menu /> <SignInButtons /> </nav> ); };

Vamos a crear un componente <Button> base para poder reusarlo asignándole variantes.

const Button = ({ children, className, mode = "ghost", chevron, }: { chevron?: boolean; mode?: "ghost" | "solid" | "shadow" | "primary"; className?: string; children: ReactNode; }) => { return ( <button className={cn( "py-1 px-3", "group", "hover:bg-[#1717170D]", "text-xs font-medium", "flex items-center gap-1", "rounded-lg transition-all", { "bg-transparent": mode === "ghost", "bg-[#1717170D]": mode === "solid", "border shadow-xs": mode === "shadow", "border bg-black text-white": mode === "primary", "hover:bg-black hover:ring-2 ring-black": mode === "primary", }, className )} > <span>{children}</span> {chevron && ( <span className="text-[7px] group-hover:rotate-180 transition-all"> <FaChevronDown /> </span> )} </button> ); };

Este es el componente más robusto y complejo, pero su robustez nos permite crear el resto de los componentes de manera más compacta. ▪️

const Menu = () => { return ( <section className="flex"> <Button chevron mode="solid"> Producto </Button> <Button chevron>Recursos</Button> <Button chevron>Empresa</Button> <Button>Industria</Button> <Button>Precios</Button> </section> ); }; const SignInButtons = () => { return ( <Form className="flex gap-1"> <Button mode="shadow">Log in</Button> <Button mode="primary">Sign up</Button> </Form> ); };

Con unas cuántas utilidades de TailwindCSS, estamos listos para añadir el panel y luego su animación.

Segunda parte: Los paneles de opciones

He tenido que construir los tres diferentes paneles. Con el propósito de no detenernos demasiado en el maquetado, te dejo el código en los enlaces y por ahora los usaremos importándolos.

export const AnimatedNavBar = () => { const [hover, setHover] = useState(""); return ( <nav onMouseLeave={() => setHover("")} className={cn( "relative", "px-4 mx-auto max-w-5xl flex justify-around items-center h-14 bg-white" )} > <Logo /> <Menu onHover={(name: string) => setHover(name)} /> <SignInButtons /> <Panel id={hover} direction={hover === "producto" ? -1 : 1} layout={ hover === "producto" ? ( <ProductLayout /> ) : hover === "recursos" ? ( <ResourcesLayout /> ) : hover === "empresa" ? ( <CompanyLayout /> ) : null } /> </nav> ); };

Nuestro componente <Panel> queda así y estamos listos para concentrarnos en lo mero bueno: las animaciones. 🤓🪄

Tercera parte: Animación con layout

Vamos a fingir, como le hacemos siempre en la vida pero ahora en el tutorial. Vamos a simular que el contenedor cambia de tamaño según se navega entre botones, pero será falso, solo parecerá que se reajusta pero en realidad es la misma animación una y otra vez. ➿

const Panel = ({ direction = 1, id, layout, currentHover, }: { currentHover?: string; direction?: number; id: string; layout: ReactNode; }) => { return currentHover === "" ? null : ( <motion.section transition={{ type: "spring", bounce: 0.2 }} initial={{ width: "672px", height: 300, x: direction * 10, filter: "blur(1px)", }} animate={{ width: "auto", height: "auto", x: 0, filter: "blur(0px)" }} key={id} className={cn( "max-w-2xl", "rounded-3xl", "overflow-hidden", "absolute border bg-white h-max shadow top-14" )} > {layout} </motion.section> ); };

Para lograrlo, hemos transformado el panel en un componente <motion> al que se le han dado los props: animate e initial. Así como una key que cambiará detonando las animaciones. Animaremos con height y width ”auto". Necesitamos de un prop: currentHover, para que nos ayude a saber si mostrar el layout o mejor devolvemos null. 🤔

Ahí está, pues. Fíjate con qué poco se puede hacer tanto. 🪄✨💬

Abrazo. Bliss. 🤓

Enlaces relacionados

Aquí está todo el código

Inspiración

meta cover

White Noise

Checa este otro Post

meta cover

¿Qué es un agente AI?

Checa este otro Post

¡Nuevo curso!

Animaciones web con React + Motion 🧙🏻