diff --git a/src/components/cart-flight.tsx b/src/components/cart-flight.tsx index 0a44e43..8af9841 100644 --- a/src/components/cart-flight.tsx +++ b/src/components/cart-flight.tsx @@ -7,6 +7,16 @@ const FLIGHT_EVENT = "wh:cart-flight"; const LAND_EVENT = "wh:cart-landed"; const FLIGHT_MS = 700; +// Nachspiel am Warenkorb-Symbol (components/cart-landing-effect.tsx): der +// Tropfen, der nach der Landung am Korb herunterlaeuft. Hier definiert, +// weil die Schublade erst oeffnen soll, wenn er fertig abgeperlt ist. +export const DRIP_DELAY_S = 0.3; +export const DRIP_DURATION_S = 1.1; +const DRAWER_AFTER_DRIP_MS = Math.round((DRIP_DELAY_S + DRIP_DURATION_S) * 1000); +// Ohne sichtbaren Flug (reduzierte Bewegung, Symbol nicht im Bild) gibt es +// nichts abzuwarten — die Schublade oeffnet fast sofort. +const DRAWER_WITHOUT_FLIGHT_MS = 180; + /** * Startet den Flug eines Honigtropfens vom geklickten Knopf zum * Warenkorb-Symbol. Aufrufer legen den Artikel mit openDrawer: false in den @@ -28,9 +38,10 @@ export function onCartLanded(handler: () => void): () => void { /** * Der Hoehepunkt des Einkaufens: ein Tropfen in Wabenform loest sich vom * Knopf, fliegt im Bogen zum Warenkorb und "tropft" hinein. Danach wippt - * der Korb, der Zaehler springt, und die Schublade oeffnet sich — Ursache - * und Wirkung werden sichtbar verbunden, statt dass die Schublade ohne - * Vorwarnung von der Seite hereinschiebt. + * der Korb, leuchtet auf, ein kleiner Tropfen laeuft an ihm herunter — und + * erst wenn der abgeperlt ist, oeffnet sich die Schublade. Ursache und + * Wirkung werden sichtbar verbunden, statt dass die Schublade ohne + * Vorwarnung von der Seite hereinschiebt und das Nachspiel verdeckt. * * Reduzierte Bewegung / Symbol nicht sichtbar (z.B. weggescrollter Header * auf kleinen Geraeten): kein Flug, die Schublade oeffnet sofort. @@ -39,9 +50,9 @@ export function CartFlight() { const openCart = useCartStore((s) => s.openCart); useEffect(() => { - const land = () => { + const land = (drawerDelayMs: number) => { window.dispatchEvent(new Event(LAND_EVENT)); - window.setTimeout(openCart, 180); + window.setTimeout(openCart, drawerDelayMs); }; const onFlight = (event: Event) => { @@ -53,7 +64,7 @@ export function CartFlight() { targetRect && targetRect.width > 0 && targetRect.bottom > 0 && targetRect.top < window.innerHeight; if (reduceMotion || !targetRect || !targetVisible) { - land(); + land(DRAWER_WITHOUT_FLIGHT_MS); return; } @@ -83,11 +94,11 @@ export function CartFlight() { ); animation.onfinish = () => { drop.remove(); - land(); + land(DRAWER_AFTER_DRIP_MS); }; animation.oncancel = () => { drop.remove(); - land(); + land(DRAWER_WITHOUT_FLIGHT_MS); }; }; diff --git a/src/components/cart-landing-effect.tsx b/src/components/cart-landing-effect.tsx index 001e1c6..66e5125 100644 --- a/src/components/cart-landing-effect.tsx +++ b/src/components/cart-landing-effect.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { motion, useAnimationControls, useReducedMotion } from "motion/react"; -import { onCartLanded } from "@/components/cart-flight"; +import { onCartLanded, DRIP_DELAY_S, DRIP_DURATION_S } 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 @@ -10,7 +10,6 @@ import { onCartLanded } from "@/components/cart-flight"; 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): @@ -53,7 +52,7 @@ export function CartLandingEffect() { scaleY: [0.2, 1, 1.35, 1, 0.8], y: [0, 0, 3, 13, 17], transition: { - duration: 1.1, + duration: DRIP_DURATION_S, delay: DRIP_DELAY_S, ease: "easeIn", times: [0, 0.3, 0.55, 0.85, 1],