Add the same badge pulse animation to the wishlist icon as the cart icon

Same mount-guard pattern as CartLink's own pulse fix — useWishlist()'s
count only fills in after its client-side fetch resolves, so without the
guard this would have pulsed on every page load too, not just a real
add/remove during the session. Fires on either direction (add or
remove) since the wishlist has no separate "flying" animation like the
cart's ball-to-icon effect to lean on instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018unaXmuzVA8ct1b6WoyP1U
This commit is contained in:
Marco
2026-07-31 22:54:42 +00:00
parent 9f61322604
commit 8b636bef25
+34 -2
View File
@@ -142,6 +142,28 @@ function AccountLink() {
// to 320px that this fits without wrapping/overflow (see git history).
function WishlistLink() {
const { count } = useWishlist();
const [pulse, setPulse] = useState(false);
const prevCountRef = useRef(0);
// Same guard as CartLink's own — useWishlist() starts from an empty
// cached/SSR-safe list and only fills in the real count once its own
// fetch resolves client-side, so without this the badge pulsed on every
// page load/reload the instant that first real count arrived, not just
// on an actual add/remove during the session.
const hasMountedRef = useRef(false);
useEffect(() => {
if (!hasMountedRef.current) {
hasMountedRef.current = true;
prevCountRef.current = count;
return;
}
if (count !== prevCountRef.current) {
setPulse(true);
const t = setTimeout(() => setPulse(false), 350);
prevCountRef.current = count;
return () => clearTimeout(t);
}
}, [count]);
return (
<Link
@@ -149,7 +171,12 @@ function WishlistLink() {
aria-label={count > 0 ? `Merkliste, ${count} Artikel` : "Merkliste"}
className="relative flex h-11 w-11 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
>
<svg viewBox="0 0 20 18" className="h-6 w-6 text-text-primary" fill="none" aria-hidden="true">
<svg
viewBox="0 0 20 18"
className={"h-6 w-6 text-text-primary transition-transform duration-300 " + (pulse ? "scale-110" : "scale-100")}
fill="none"
aria-hidden="true"
>
<path
d="M10 17S1 11.5 1 5.8C1 2.6 3.4 1 5.8 1c1.6 0 3.2.9 4.2 2.4C11 1.9 12.6 1 14.2 1 16.6 1 19 2.6 19 5.8 19 11.5 10 17 10 17Z"
stroke="currentColor"
@@ -158,7 +185,12 @@ function WishlistLink() {
/>
</svg>
{count > 0 && (
<span className="absolute top-0 right-0 flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-brand px-1 text-[0.6875rem] font-bold leading-none text-white">
<span
className={
"absolute top-0 right-0 flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-brand px-1 text-[0.6875rem] font-bold leading-none text-white transition-transform duration-300 " +
(pulse ? "scale-125" : "scale-100")
}
>
{count > 99 ? "99+" : count}
</span>
)}