The landing glow was a larger, filled basket with a thicker stroke and a blurred halo, so the icon looked bigger during the effect. The glow is now an exact copy of the icon (same size, same stroke width, no fill, no scaling) that only changes colour to honey for a moment. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
118 lines
4.1 KiB
TypeScript
118 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect } from "react";
|
|
import { motion, useAnimationControls, useReducedMotion } from "motion/react";
|
|
import { onCartLanded } from "@/components/cart-flight";
|
|
|
|
// Der Korb im Kopfzeilen-Symbol (20 px in einem 40-px-Knopf, viewBox 24):
|
|
// seine Unterkante liegt bei y=15, die Mitte bei x=13.5. Dort bildet sich
|
|
// der Tropfen — umgerechnet in Pixel des Knopfes.
|
|
const DRIP_LEFT_PX = 10 + (13.5 / 24) * 20;
|
|
const DRIP_TOP_PX = 10 + (15 / 24) * 20;
|
|
const DRIP_WIDTH_PX = 6;
|
|
const DRIP_DELAY_S = 0.3;
|
|
|
|
/**
|
|
* Nachspiel der Landung eines Honigtropfens (components/cart-flight.tsx):
|
|
* Der Korb leuchtet zweimal warm in Honigfarbe auf, dann sammelt sich an
|
|
* seiner Unterkante ein kleiner Tropfen, zieht sich lang und perlt nach
|
|
* unten ab — als waere der Honig durch den Korb gesickert.
|
|
*
|
|
* Liegt als Overlay im Warenkorb-Knopf (relative) und faengt keine Klicks.
|
|
* Das Leuchten ist eine deckungsgleiche, honigfarbene Kopie des Korbs (gleiche
|
|
* Groesse, gleiche Strichstaerke, keine Fuellung), deren Deckkraft blinkt.
|
|
* Das Symbol selbst bleibt unveraendert; nur seine Farbe wechselt kurz — im
|
|
* hellen wie im dunklen Farbschema. Bei reduzierter Bewegung
|
|
* bleibt nur ein einzelnes, ruhiges Aufleuchten ohne Tropfen.
|
|
*/
|
|
export function CartLandingEffect() {
|
|
const glowControls = useAnimationControls();
|
|
const dripControls = useAnimationControls();
|
|
const reduceMotion = useReducedMotion();
|
|
|
|
useEffect(
|
|
() =>
|
|
onCartLanded(() => {
|
|
if (reduceMotion) {
|
|
void glowControls.start({
|
|
opacity: [0, 0.9, 0],
|
|
transition: { duration: 0.8, ease: "easeInOut" },
|
|
});
|
|
return;
|
|
}
|
|
|
|
void glowControls.start({
|
|
opacity: [0, 1, 0.35, 1, 0],
|
|
transition: { duration: 0.75, ease: "easeInOut", times: [0, 0.2, 0.45, 0.65, 1] },
|
|
});
|
|
void dripControls.start({
|
|
// An der Kante sammeln, schwer werden und lang ziehen,
|
|
// abloesen und nach unten perlen, verblassen.
|
|
opacity: [0, 1, 1, 1, 0],
|
|
scaleX: [0.3, 1, 0.85, 0.9, 0.7],
|
|
scaleY: [0.2, 1, 1.35, 1, 0.8],
|
|
y: [0, 0, 3, 13, 17],
|
|
transition: {
|
|
duration: 1.1,
|
|
delay: DRIP_DELAY_S,
|
|
ease: "easeIn",
|
|
times: [0, 0.3, 0.55, 0.85, 1],
|
|
},
|
|
});
|
|
}),
|
|
[glowControls, dripControls, reduceMotion]
|
|
);
|
|
|
|
return (
|
|
<span aria-hidden="true" className="pointer-events-none absolute inset-0">
|
|
<motion.span
|
|
initial={{ opacity: 0 }}
|
|
animate={glowControls}
|
|
className="absolute inset-0 flex items-center justify-center"
|
|
>
|
|
<svg
|
|
className="text-honey drop-shadow-[0_0_3px_var(--color-honey)]"
|
|
width="20"
|
|
height="20"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
>
|
|
<path d="M6 6h15l-1.5 9h-12z" />
|
|
<path d="M6 6 5 3H2" />
|
|
<circle cx="9" cy="20" r="1" />
|
|
<circle cx="18" cy="20" r="1" />
|
|
</svg>
|
|
</motion.span>
|
|
|
|
{reduceMotion ? null : (
|
|
<motion.span
|
|
initial={{ opacity: 0 }}
|
|
animate={dripControls}
|
|
style={{
|
|
left: DRIP_LEFT_PX - DRIP_WIDTH_PX / 2,
|
|
top: DRIP_TOP_PX - 1,
|
|
width: DRIP_WIDTH_PX,
|
|
transformOrigin: "50% 0%",
|
|
}}
|
|
className="absolute"
|
|
>
|
|
{/* Gleiche Honigtoene wie der fliegende Tropfen in cart-flight.tsx. */}
|
|
<svg viewBox="0 0 6 9" width={DRIP_WIDTH_PX} height="9">
|
|
<defs>
|
|
<radialGradient id="wh-drip" cx="40%" cy="65%" r="70%">
|
|
<stop offset="0" stopColor="#e4cfa4" />
|
|
<stop offset="0.5" stopColor="#b88a44" />
|
|
<stop offset="1" stopColor="#8a6531" />
|
|
</radialGradient>
|
|
</defs>
|
|
<path d="M3 0C3 2.5 6 4.2 6 6.1A3 3 0 0 1 0 6.1C0 4.2 3 2.5 3 0Z" fill="url(#wh-drip)" />
|
|
<ellipse cx="2" cy="5.8" rx="0.7" ry="1" fill="#fff" opacity="0.6" />
|
|
</svg>
|
|
</motion.span>
|
|
)}
|
|
</span>
|
|
);
|
|
}
|