feat(web): add persistent appointment button
This commit is contained in:
parent
157dfbf186
commit
528d9766ed
58
web/src/components/FloatingBookingButton.css
Normal file
58
web/src/components/FloatingBookingButton.css
Normal file
@ -0,0 +1,58 @@
|
||||
/* One fixed stack keeps booking and cookie consent from covering each other. */
|
||||
.booking-dock {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 80;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 12px;
|
||||
padding: 20px;
|
||||
padding-right: max(20px, env(safe-area-inset-right));
|
||||
padding-bottom: max(20px, env(safe-area-inset-bottom));
|
||||
padding-left: max(20px, env(safe-area-inset-left));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.floating-booking {
|
||||
min-height: 54px;
|
||||
max-width: 100%;
|
||||
padding: 0 24px;
|
||||
font-size: 16px;
|
||||
box-shadow: 0 6px 22px rgba(242, 97, 84, 0.3);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.floating-booking svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.floating-booking:focus-visible {
|
||||
outline: 3px solid var(--navy);
|
||||
outline-offset: 4px;
|
||||
}
|
||||
|
||||
.booking-dock > .cookie-banner {
|
||||
position: static;
|
||||
align-self: center;
|
||||
width: min(900px, 100%);
|
||||
transform: none;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.booking-dock {
|
||||
padding: 12px;
|
||||
padding-right: max(12px, env(safe-area-inset-right));
|
||||
padding-bottom: max(12px, env(safe-area-inset-bottom));
|
||||
padding-left: max(12px, env(safe-area-inset-left));
|
||||
}
|
||||
|
||||
.floating-booking {
|
||||
min-height: 50px;
|
||||
padding: 0 20px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
21
web/src/components/FloatingBookingButton.jsx
Normal file
21
web/src/components/FloatingBookingButton.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { useLeadModal } from '../context/LeadModalContext.jsx';
|
||||
import './FloatingBookingButton.css';
|
||||
|
||||
export default function FloatingBookingButton() {
|
||||
const { open } = useLeadModal();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn--coral floating-booking"
|
||||
onClick={() => open({ form: 'appointment' })}
|
||||
aria-haspopup="dialog"
|
||||
>
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<rect x="3" y="5" width="18" height="16" rx="3" />
|
||||
<path d="M16 3v4M8 3v4M3 11h18M9 16h6M12 13v6" />
|
||||
</svg>
|
||||
Записаться
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@ -3,6 +3,7 @@ import { Outlet, useLocation } from 'react-router-dom';
|
||||
import Header from './Header.jsx';
|
||||
import Footer from './Footer.jsx';
|
||||
import CookieBanner from './CookieBanner.jsx';
|
||||
import FloatingBookingButton from './FloatingBookingButton.jsx';
|
||||
import { SiteDataProvider } from '../context/SiteData.jsx';
|
||||
import { LeadModalProvider } from '../context/LeadModalContext.jsx';
|
||||
import { getConsent, hit, startMetrika } from '../lib/metrika.js';
|
||||
@ -33,7 +34,10 @@ export default function Layout() {
|
||||
<Outlet />
|
||||
</main>
|
||||
<Footer />
|
||||
<CookieBanner />
|
||||
<div className="booking-dock">
|
||||
<FloatingBookingButton />
|
||||
<CookieBanner />
|
||||
</div>
|
||||
</div>
|
||||
</LeadModalProvider>
|
||||
</SiteDataProvider>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user