60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useRef } from "react";
|
|
import { motion } from "framer-motion";
|
|
import { IoCartOutline } from "react-icons/io5";
|
|
import { IconButton } from "@/components/IconButton";
|
|
import { useCart } from "./CartContext";
|
|
|
|
export function CartButton({ className }: { className?: string }) {
|
|
const { itemCount, setDrawerOpen } = useCart();
|
|
const hasItems = itemCount > 0;
|
|
|
|
// If the component mounts with items already in the cart (e.g. navigating
|
|
// between pages), start fully visible so there's no fade-in on every page.
|
|
const mountedWithItems = useRef(hasItems);
|
|
|
|
return (
|
|
<motion.div
|
|
className={className}
|
|
initial={{
|
|
opacity: mountedWithItems.current ? 1 : 0,
|
|
display: mountedWithItems.current ? "block" : "none",
|
|
}}
|
|
animate={
|
|
hasItems
|
|
? {
|
|
opacity: 1,
|
|
display: "block",
|
|
transition: {
|
|
type: "tween",
|
|
ease: "easeInOut",
|
|
duration: 0.2,
|
|
delay: 0.4,
|
|
},
|
|
}
|
|
: {
|
|
opacity: 0,
|
|
transition: {
|
|
type: "tween",
|
|
ease: "easeInOut",
|
|
duration: 0.2,
|
|
},
|
|
transitionEnd: {
|
|
display: "none",
|
|
},
|
|
}
|
|
}
|
|
style={{ pointerEvents: hasItems ? "auto" : "none" }}
|
|
>
|
|
<IconButton onClick={() => setDrawerOpen(true)} aria-label="Open cart" className="text-lg">
|
|
<span className="relative">
|
|
<IoCartOutline />
|
|
<span className="absolute -top-1.5 -right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-trptkblue text-xs leading-none font-bold text-white dark:bg-white dark:text-lighttext">
|
|
{itemCount}
|
|
</span>
|
|
</span>
|
|
</IconButton>
|
|
</motion.div>
|
|
);
|
|
}
|