Single-row footer strip with blur stagger on view — logo-cloud-16 footer strip DNA for wordmark, inline links, and copyright.
@nusaiba
"use client";
import Link from "next/link";
import { useRef, type PointerEvent } from "react";
import { motion, useInView, useMotionValue, useReducedMotion, useSpring } from "motion/react";
import { motionStagger, motionViewport } from "@/lib/motion-tokens";
import { cn } from "@/lib/utils";
const navLinks = [
{ href: "/blocks", label: "Blocks" },
{ href: "/motion", label: "Motion" },
{ href: "/docs", label: "Docs" },
{ href: "/pricing", label: "Pricing" },
] as const;
const linkClass = cn(
"relative inline-flex min-h-10 items-center px-2.5 text-muted-foreground text-xs transition-[color,transform] hover:text-foreground",
"after:absolute after:top-1/2 after:left-1/2 after:size-10 after:-translate-1/2",
"active:scale-[0.96]",
);
const magneticSpring = { stiffness: 420, damping: 32, mass: 0.4 };
const maxOffset = 4;
function MagneticLink({
href,
label,
reduceMotion,
highlight,
}: {
href: string;
label: string;
reduceMotion: boolean;
highlight?: boolean;
}) {
const ref = useRef<HTMLDivElement>(null);
const x = useMotionValue(0);
const y = useMotionValue(0);
const springX = useSpring(x, magneticSpring);
const springY = useSpring(y, magneticSpring);
function onPointerMove(event: PointerEvent<HTMLDivElement>) {
if (reduceMotion || !ref.current) return;
const rect = ref.current.getBoundingClientRect();
const dx = event.clientX - (rect.left + rect.width / 2);
const dy = event.clientY - (rect.top + rect.height / 2);
const influence = Math.max(0, 1 - Math.hypot(dx, dy) / 120);
x.set(Math.max(-maxOffset, Math.min(maxOffset, dx * influence * 0.08)));
y.set(Math.max(-maxOffset, Math.min(maxOffset, dy * influence * 0.08)));
}
function onPointerLeave() {
x.set(0);
y.set(0);
}
return (
<motion.div
onPointerLeave={onPointerLeave}
onPointerMove={onPointerMove}
ref={ref}
style={reduceMotion ? undefined : { x: springX, y: springY }}
>
<Link
className={cn(
linkClass,
highlight && "font-medium text-primary",
)}
href={href}
>
{label}
</Link>
</motion.div>
);
}
type FooterBaseStripProps = {
magneticNav?: boolean;
};
export function FooterBaseStrip({ magneticNav = false }: FooterBaseStripProps) {
const reduceMotion = useReducedMotion();
const rowRef = useRef<HTMLDivElement>(null);
const inView = useInView(rowRef, motionViewport);
const year = new Date().getFullYear();
const itemVariants = reduceMotion
? { hidden: { opacity: 1 }, visible: { opacity: 1 } }
: {
hidden: { opacity: 0, filter: "blur(4px)", y: 4 },
visible: { opacity: 1, filter: "blur(0px)", y: 0 },
};
return (
<div className="px-4 py-6 md:py-7">
<motion.div
animate={inView ? "visible" : "hidden"}
className="mx-auto flex w-full max-w-5xl flex-col items-center justify-between gap-4 md:flex-row md:gap-6"
initial="hidden"
ref={rowRef}
variants={{
hidden: {},
visible: {
transition: {
staggerChildren: motionStagger.item,
delayChildren: 0.03,
},
},
}}
>
<motion.div variants={itemVariants}>
<Link
className={cn(
linkClass,
"px-0 font-medium text-foreground text-sm tracking-[-0.04em]",
)}
href="/"
>
Nusaiba
</Link>
</motion.div>
<motion.nav
aria-label="Footer"
className="flex flex-wrap items-center justify-center gap-x-0.5 gap-y-0.5"
variants={itemVariants}
>
{navLinks.map((link) =>
magneticNav ? (
<MagneticLink
highlight={link.label === "Pricing"}
href={link.href}
key={link.href}
label={link.label}
reduceMotion={!!reduceMotion}
/>
) : (
<Link className={linkClass} href={link.href} key={link.href}>
{link.label}
</Link>
),
)}
</motion.nav>
<motion.p
className="text-muted-foreground text-xs tabular-nums"
variants={itemVariants}
>
© {year} Nusaiba
</motion.p>
</motion.div>
</div>
);
}





























