| 1 |
"use client"; |
| 2 |
|
| 3 |
import { useState, useEffect } from "react"; |
| 4 |
|
| 5 |
const BLUR_PLACEHOLDER = |
| 6 |
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDACgcHiMeGSgjISMtKygwPGRBPDc3PHtYXUlkkYCZlo+AjIqgtObDoKrarYqMyP/L2u71////m8H////6/+b9//j/2wBDASstLTw1PHZBQXb4pYyl+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj/wAARCAALABQDAREAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAABAABA//EACAQAAIBAwQDAAAAAAAAAAAAAAECAAMEERQhMUFicZH/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/EABgRAQEBAQEAAAAAAAAAAAAAAAACEgER/9oADAMBAAIRAxEAPwBKXTNwoz7hmVrqnumU7gR5Mr2metbx+RzI9oakSMYMClVie5IcmKf/2Q=="; |
| 7 |
|
| 8 |
export default function ProgressiveHero({ |
| 9 |
children, |
| 10 |
}: { |
| 11 |
children: React.ReactNode; |
| 12 |
}) { |
| 13 |
const [loaded, setLoaded] = useState(false); |
| 14 |
|
| 15 |
useEffect(() => { |
| 16 |
const img = new Image(); |
| 17 |
img.onload = () => setLoaded(true); |
| 18 |
img.src = "/hero-tarmac-1920.jpg"; |
| 19 |
}, []); |
| 20 |
|
| 21 |
return ( |
| 22 |
<div className="relative min-h-screen"> |
| 23 |
{/* Blur placeholder — always visible immediately */} |
| 24 |
<div |
| 25 |
className="fixed inset-0 z-0 transition-opacity duration-700" |
| 26 |
style={{ |
| 27 |
backgroundImage: `url(${BLUR_PLACEHOLDER})`, |
| 28 |
backgroundSize: "cover", |
| 29 |
backgroundPosition: "center", |
| 30 |
filter: "blur(20px)", |
| 31 |
transform: "scale(1.1)", |
| 32 |
opacity: loaded ? 0 : 1, |
| 33 |
}} |
| 34 |
/> |
| 35 |
|
| 36 |
{/* Full-res hero — fades in when loaded */} |
| 37 |
<div |
| 38 |
className="fixed inset-0 z-0 transition-opacity duration-700" |
| 39 |
style={{ |
| 40 |
backgroundImage: `url(/hero-tarmac-1920.jpg)`, |
| 41 |
backgroundSize: "cover", |
| 42 |
backgroundPosition: "center", |
| 43 |
opacity: loaded ? 1 : 0, |
| 44 |
}} |
| 45 |
/> |
| 46 |
|
| 47 |
{/* Content layer */} |
| 48 |
<div className="relative z-10">{children}</div> |
| 49 |
</div> |
| 50 |
); |
| 51 |
} |