-
-
Save ejabu/36088614d10d0321c17ae712f061c0c3 to your computer and use it in GitHub Desktop.
In View component React Motion
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## MUNCUL BASED ON SCROLL | |
| "use client"; | |
| import { AnimatePresence, motion, Variants } from "motion/react"; | |
| import Link from "next/link"; | |
| import { useEffect, useRef, useState } from "react"; | |
| import { NewFadeIn } from "@/components/layout/new-fade-in"; | |
| import FadeUp from "@/components/motion/fade-up"; | |
| import { HamburgerButton } from "@/features/components/hamburger-button"; | |
| import { KitButton } from "@/features/components/kit-button"; | |
| import { MobileDrawer } from "@/features/components/mobile-drawer"; | |
| type NavItem = { label: string; href: string }; | |
| export default function TopNav({ | |
| secondSectionId = "section-2", | |
| items = [ | |
| { label: "About Us", href: "/about-us" }, | |
| { label: "Programs", href: "#programs" }, | |
| { label: "Industry Innovation", href: "/industry-and-ai-innovation" }, | |
| { label: "Contact Us", href: "/contact-us" }, | |
| ], | |
| }: { | |
| secondSectionId?: string; | |
| items?: NavItem[]; | |
| }) { | |
| const [solid, setSolid] = useState(false); | |
| const [open, setOpen] = useState(false); | |
| const observedRef = useRef<HTMLElement | null>(null); | |
| // Watch the 2nd section | |
| useEffect(() => { | |
| const target = document.getElementById(secondSectionId); | |
| observedRef.current = target as HTMLElement | null; | |
| if (!target) return; | |
| const io = new IntersectionObserver( | |
| ([entry]) => { | |
| // When section-2 is intersecting (on screen), nav becomes solid | |
| setSolid(entry!.isIntersecting); | |
| }, | |
| { | |
| // Trigger as soon as the section’s top is near the top of the viewport | |
| root: null, | |
| // top offset so it flips just before/around the section enters | |
| // rootMargin: "0px", | |
| rootMargin: "-10% 0px -70% 0px", | |
| threshold: [0, 0.1, 0.5, 1], | |
| // threshold: 0, | |
| // rootMargin: "10% 0px -90% 0px", | |
| // threshold: [0, 0.1, 0.5, 1], | |
| }, | |
| ); | |
| io.observe(target); | |
| return () => io.disconnect(); | |
| }, [secondSectionId]); | |
| const drawerVariants = { | |
| open: { | |
| x: 0, | |
| transition: { | |
| ease: "easeInOut", | |
| duration: 0.5, | |
| when: "beforeChildren", | |
| staggerChildren: 0.06, | |
| delayChildren: 0.05, | |
| }, | |
| }, | |
| closed: { | |
| x: "100%", | |
| transition: { ease: "easeInOut", duration: 0.4 }, | |
| }, | |
| } as Variants; | |
| const itemVariants = { | |
| open: { opacity: 1, x: 0, transition: { duration: 0.25 } }, | |
| closed: { opacity: 0, x: 16, transition: { duration: 0.15 } }, | |
| } as Variants; | |
| return ( | |
| <motion.nav | |
| initial={false} | |
| animate={{ | |
| backgroundColor: solid ? "rgba(0,0,0,0.65)" : "rgba(0,0,0,0.0)", | |
| paddingTop: solid ? "8px" : "24px", | |
| backdropFilter: solid ? "blur(6px)" : "blur(0px)", | |
| }} | |
| transition={{ type: "spring", stiffness: 220, damping: 28 }} | |
| className="fixed inset-x-0 top-0 z-50" | |
| aria-label="Top Navigation" | |
| > | |
| <div className="mx-auto py-2 md:py-8 px-4 lg:py-4 lg:px-16"> | |
| <div className="flex h-16 items-center justify-between"> | |
| {/* Logo */} | |
| <FadeUp delay={1.6} rotateX={0} initY={0}> | |
| <Link href="/" className="flex items-center gap-3"> | |
| {/* Replace with your SVG/Img logo */} | |
| <img src="/assets/images/logo-mbzuai.svg" className="w-40 lg:w-48 xl:w-60" /> | |
| {/* <div className="size-8 rounded-full bg-white" /> | |
| <div className="text-white"> | |
| <div className="text-sm font-semibold leading-none">Mohamed bin Zayed</div> | |
| <div className="text-[11px] opacity-80 leading-none">University of Artificial Intelligence</div> | |
| </div> */} | |
| </Link> | |
| </FadeUp> | |
| {/* Desktop nav */} | |
| <FadeUp delay={1.6} rotateX={0} initY={0}> | |
| <div className="hidden lg:flex items-center gap-8"> | |
| {items.map((it) => ( | |
| <a | |
| key={it.label} | |
| href={it.href} | |
| className="text-white/90 hover:text-white transition-colors hover:underline" | |
| > | |
| {it.label} | |
| </a> | |
| ))} | |
| <KitButton text="Visit Us" showArrow={false} /> | |
| </div> | |
| </FadeUp> | |
| {/* Mobile menu button */} | |
| <div className="lg:hidden"> | |
| <HamburgerButton open={open} toggle={() => setOpen((v) => !v)} /> | |
| </div> | |
| {/* <button | |
| onClick={() => setOpen((v) => !v)} | |
| className="lg:hidden inline-flex items-center justify-center rounded-md p-2 text-white/90 hover:text-white z-100" | |
| aria-label="Toggle Menu" | |
| > | |
| <span className="sr-only">Open menu</span> | |
| <div className="space-y-1"> | |
| <span className="block h-0.5 w-6 bg-white"></span> | |
| <span className="block h-0.5 w-6 bg-white"></span> | |
| <span className="block h-0.5 w-6 bg-white"></span> | |
| </div> | |
| </button> */} | |
| </div> | |
| </div> | |
| {/* Mobile drawer */} | |
| <MobileDrawer | |
| open={open} | |
| setOpen={() => setOpen(false)} | |
| items={[ | |
| { label: "About", href: "#about" }, | |
| { | |
| label: "Programs", | |
| children: [ | |
| { label: "University Collaboration", href: "#ms" }, | |
| { label: "MBZUAI On the Road", href: "#ms" }, | |
| { label: "MBZUAI Research Program", href: "#ms" }, | |
| { label: "Industry Liason Program", href: "#ms" }, | |
| ], | |
| }, | |
| { label: "MBZUAI on the road", href: "#road" }, | |
| { label: "Contact Us", href: "#contact" }, | |
| { label: "Visit Us", href: "#visit" }, | |
| ]} | |
| /> | |
| </motion.nav> | |
| ); | |
| } | |
| ## MUNCUL | |
| ## CLIENT | |
| <FadeUp> | |
| <h3 className="page-heading-sm mb-4">Give props to your block content</h3> | |
| </FadeUp> | |
| ## Fade Up File | |
| import { PropsWithChildren, ReactNode } from "react"; | |
| import { InView } from "@/components/ui/in-view"; | |
| type FadeUpProps = PropsWithChildren<{ | |
| delay?: number; | |
| duration?: number; | |
| initY?: number; | |
| rotateX?: number; | |
| as?: any; | |
| className?: string; | |
| }>; | |
| const FadeUp = ({ | |
| children, | |
| delay = 0, | |
| duration = 0.3, | |
| initY = 20, | |
| rotateX = -90, | |
| }: FadeUpProps) => { | |
| return ( | |
| <InView | |
| variants={{ | |
| hidden: { opacity: 0, y: initY, rotateX: rotateX }, | |
| visible: { opacity: 1, y: 0, rotateX: 0 }, | |
| }} | |
| viewOptions={{ | |
| once: true, | |
| }} | |
| transition={{ duration: duration, ease: "easeInOut", delay: delay }} | |
| > | |
| {children} | |
| </InView> | |
| ); | |
| }; | |
| export default FadeUp; | |
| ## COmponents IN view | |
| 'use client'; | |
| import { ReactNode, useRef, useState } from 'react'; | |
| import { | |
| motion, | |
| useInView, | |
| Variant, | |
| Transition, | |
| UseInViewOptions, | |
| } from 'motion/react'; | |
| export type InViewProps = { | |
| children: ReactNode; | |
| variants?: { | |
| hidden: Variant; | |
| visible: Variant; | |
| }; | |
| transition?: Transition; | |
| viewOptions?: UseInViewOptions; | |
| as?: React.ElementType; | |
| once?: boolean | |
| }; | |
| const defaultVariants = { | |
| hidden: { opacity: 0 }, | |
| visible: { opacity: 1 }, | |
| }; | |
| export function InView({ | |
| children, | |
| variants = defaultVariants, | |
| transition, | |
| viewOptions, | |
| as = 'div', | |
| once | |
| }: InViewProps) { | |
| const ref = useRef(null); | |
| const isInView = useInView(ref, viewOptions); | |
| const [isViewed, setIsViewed] = useState(false) | |
| const MotionComponent = motion[as as keyof typeof motion] as typeof as; | |
| return ( | |
| <MotionComponent | |
| ref={ref} | |
| initial='hidden' | |
| onAnimationComplete={() => { | |
| if (once) setIsViewed(true) | |
| }} | |
| animate={(isInView || isViewed) ? "visible" : "hidden"} | |
| variants={variants} | |
| transition={transition} | |
| > | |
| {children} | |
| </MotionComponent> | |
| ); | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
use motion/react like in https://github.com/uaebdg/app-template/blob/e00d1eeb727ead4ae00162f0d50f30d89d5c77d2/src/app/lab/modal-10/page.tsx#L3