feat(web): add persistent appointment button

This commit is contained in:
Dana Medical Developer 2026-10-20 13:08:40 +00:00
parent 157dfbf186
commit 528d9766ed
3 changed files with 84 additions and 1 deletions

View 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;
}
}

View 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>
);
}

View File

@ -3,6 +3,7 @@ import { Outlet, useLocation } from 'react-router-dom';
import Header from './Header.jsx'; import Header from './Header.jsx';
import Footer from './Footer.jsx'; import Footer from './Footer.jsx';
import CookieBanner from './CookieBanner.jsx'; import CookieBanner from './CookieBanner.jsx';
import FloatingBookingButton from './FloatingBookingButton.jsx';
import { SiteDataProvider } from '../context/SiteData.jsx'; import { SiteDataProvider } from '../context/SiteData.jsx';
import { LeadModalProvider } from '../context/LeadModalContext.jsx'; import { LeadModalProvider } from '../context/LeadModalContext.jsx';
import { getConsent, hit, startMetrika } from '../lib/metrika.js'; import { getConsent, hit, startMetrika } from '../lib/metrika.js';
@ -33,7 +34,10 @@ export default function Layout() {
<Outlet /> <Outlet />
</main> </main>
<Footer /> <Footer />
<CookieBanner /> <div className="booking-dock">
<FloatingBookingButton />
<CookieBanner />
</div>
</div> </div>
</LeadModalProvider> </LeadModalProvider>
</SiteDataProvider> </SiteDataProvider>