TypeScript · 1759 bytes Raw Blame History
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 }