// Layout.jsx — Header, Footer, QuoteBar, ContactModal
function Header({ onContactClick }) {
const { path, navigate } = useRouter();
const [scrolled, setScrolled] = React.useState(false);
const [mobileOpen, setMobileOpen] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 8);
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
return () => window.removeEventListener('scroll', onScroll);
}, []);
React.useEffect(() => { setMobileOpen(false); }, [path]);
const links = [
{ to: '/', label: 'Home' },
{ to: '/services', label: 'Services' },
{ to: '/about', label: 'About' },
{ to: '/blog', label: 'Blog' },
{ to: '/contact', label: 'Contact' },
];
const isActive = (to) => to === '/' ? path === '/' : path === to || path.startsWith(to + '/');
return (
);
}
function Footer() {
const cols = [
{ title: 'Services', links: SERVICES.map(s => ({ label: s.title, to: '/services/' + s.slug })) },
{ title: 'Company', links: [
{ label: 'About us', to: '/about' },
{ label: 'Blog', to: '/blog' },
{ label: 'Contact', to: '/contact' },
]},
];
return (
);
}
function QuoteBar({ onClick }) {
const [show, setShow] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setShow(window.scrollY > 400);
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
return () => window.removeEventListener('scroll', onScroll);
}, []);
return (
);
}
function ContactModal({ open, onClose }) {
const [submitted, setSubmitted] = React.useState(false);
const [submitting, setSubmitting] = React.useState(false);
const [error, setError] = React.useState(null);
React.useEffect(() => {
if (!open) { setSubmitted(false); setError(null); }
if (open) {
const onKey = (e) => { if (e.key === 'Escape') onClose(); };
window.addEventListener('keydown', onKey);
document.body.style.overflow = 'hidden';
return () => { window.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
}
}, [open]);
if (!open) return null;
const handleSubmit = async (e) => {
e.preventDefault();
setSubmitting(true);
setError(null);
try {
await submitToFormspree(new FormData(e.target));
setSubmitted(true);
} catch {
setError('Something went wrong. Please try again or call us directly.');
} finally {
setSubmitting(false);
}
};
return (
e.stopPropagation()} style={{
background: '#fff', borderRadius: 'var(--radius-2xl)',
maxWidth: 520, width: '100%', padding: 36,
boxShadow: 'var(--shadow-xl)', position: 'relative',
maxHeight: '90vh', overflow: 'auto',
}}>
{submitted ? (
Thanks — we'll be in touch.
One of our team will reply within one business day. In the meantime, feel free to call us on +350 225 02143.
) : (
<>
Get a free quote
Tell us about your business.
No obligation — we'll review your needs and reply with a clear, costed proposal.
>
)}
);
}
window.Header = Header;
window.Footer = Footer;
window.QuoteBar = QuoteBar;
window.ContactModal = ContactModal;