Skip to content

Instantly share code, notes, and snippets.

@ejabu
Last active August 29, 2025 03:24
Show Gist options
  • Select an option

  • Save ejabu/36088614d10d0321c17ae712f061c0c3 to your computer and use it in GitHub Desktop.

Select an option

Save ejabu/36088614d10d0321c17ae712f061c0c3 to your computer and use it in GitHub Desktop.
In View component React Motion
## 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>
);
}
@ejabu
Copy link
Author

ejabu commented Aug 29, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment