This commit is contained in:
commit
59bb5a38a3
132 files changed
+19435
No files matched your search
@@ -0,0 +1,69 @@
|
||||
"use client";
|
||||
|
||||
import { AnimatePresence, LazyMotion, domAnimation, m } from "motion/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { BookButton, useBooking } from "./BookingProvider";
|
||||
|
||||
/**
|
||||
* Buchungsleiste fuer kleine Bildschirme. Erscheint erst, wenn der Hero
|
||||
* verlassen ist, und verschwindet im Preisbereich und am Seitenende, damit
|
||||
* sie dort keine Inhalte oder Bedienelemente verdeckt.
|
||||
*/
|
||||
export function MobileBookingBar({ priceLabel }: { priceLabel: string }) {
|
||||
const { pricing } = useBooking();
|
||||
const [heroVisible, setHeroVisible] = useState(true);
|
||||
const [blocked, setBlocked] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const hero = document.getElementById("top");
|
||||
const blockers = ["preis", "site-footer"].map((id) => document.getElementById(id)).filter(Boolean) as HTMLElement[];
|
||||
const visible = new Set<string>();
|
||||
const heroObserver = new IntersectionObserver(([entry]) => setHeroVisible(entry?.isIntersecting ?? false));
|
||||
const blockObserver = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) visible.add(entry.target.id);
|
||||
else visible.delete(entry.target.id);
|
||||
}
|
||||
setBlocked(visible.size > 0);
|
||||
});
|
||||
if (hero) heroObserver.observe(hero);
|
||||
blockers.forEach((b) => blockObserver.observe(b));
|
||||
return () => {
|
||||
heroObserver.disconnect();
|
||||
blockObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const show = !heroVisible && !blocked;
|
||||
|
||||
return (
|
||||
<LazyMotion features={domAnimation}>
|
||||
<AnimatePresence>
|
||||
{show && (
|
||||
<m.div
|
||||
className="mobile-book-bar fixed inset-x-0 bottom-0 z-30 border-t border-line bg-plaster/95 backdrop-blur lg:hidden"
|
||||
data-visible="true"
|
||||
initial={{ y: "100%" }}
|
||||
animate={{ y: 0 }}
|
||||
exit={{ y: "100%" }}
|
||||
transition={{ duration: 0.3, ease: [0.22, 1, 0.36, 1] }}
|
||||
>
|
||||
<div className="container-edge flex items-center justify-between gap-4 py-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]">
|
||||
<p className="text-sm leading-tight">
|
||||
<span className="block font-semibold">Modelcamp 2027</span>
|
||||
<span className="text-stone">{priceLabel}</span>
|
||||
</p>
|
||||
{pricing.checkoutOpen ? (
|
||||
<BookButton className="btn btn-primary min-h-11 px-5 py-2 text-sm">Platz buchen</BookButton>
|
||||
) : (
|
||||
<a href="#preis" className="btn btn-quiet min-h-11 px-5 py-2 text-sm">
|
||||
Zum Preis
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</m.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</LazyMotion>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user