|
1 | 1 | "use client"; |
2 | 2 |
|
3 | 3 | import { useEffect, useRef, useState } from "react"; |
| 4 | +import ReactPlayer from "react-player"; |
4 | 5 | import { scheduleIdleWork } from "@/lib/schedule-idle-work"; |
5 | 6 |
|
6 | 7 | const VIDEOS = [ |
7 | | - { webm: "/rainy.webm", mp4: "/rainy.mp4", poster: "/rainy.jpg" }, |
8 | | - { webm: "/midnight.webm", mp4: "/midnight.mp4", poster: "/midnight.jpg" }, |
9 | | - { webm: "/night.webm", mp4: "/night.mp4", poster: "/night.jpg" }, |
10 | | - { webm: "/night-city.webm", mp4: "/night-city.mp4", poster: "/night-city.jpg" }, |
| 8 | + { kind: "local", webm: "/rainy.webm", mp4: "/rainy.mp4", poster: "/rainy.jpg" }, |
| 9 | + { kind: "local", webm: "/midnight.webm", mp4: "/midnight.mp4", poster: "/midnight.jpg" }, |
| 10 | + { kind: "local", webm: "/night.webm", mp4: "/night.mp4", poster: "/night.jpg" }, |
| 11 | + { kind: "local", webm: "/night-city.webm", mp4: "/night-city.mp4", poster: "/night-city.jpg" }, |
| 12 | + { |
| 13 | + kind: "youtube", |
| 14 | + id: "AUQKjgKQF7w", |
| 15 | + url: "https://www.youtube.com/watch?v=AUQKjgKQF7w", |
| 16 | + }, |
11 | 17 | ] as const; |
12 | 18 | const TABLET_MIN_WIDTH_MEDIA = "(min-width: 600px)"; |
13 | 19 |
|
14 | 20 | interface Props { |
15 | 21 | onReady?: () => void; |
| 22 | + onYouTubeEngaged?: () => void; |
16 | 23 | } |
17 | 24 |
|
18 | | -export default function HeroBackdropVideo({ onReady }: Props) { |
| 25 | +export default function HeroBackdropVideo({ onReady, onYouTubeEngaged }: Props) { |
19 | 26 | const containerRef = useRef<HTMLDivElement | null>(null); |
20 | 27 | const [isVisible, setIsVisible] = useState(false); |
21 | 28 | const [video, setVideo] = useState<(typeof VIDEOS)[number] | null>(null); |
| 29 | + const [hasInteracted, setHasInteracted] = useState(false); |
| 30 | + const [isYouTubeReady, setIsYouTubeReady] = useState(false); |
| 31 | + const isYouTubeEngaged = video?.kind === "youtube" && hasInteracted && isYouTubeReady; |
22 | 32 |
|
23 | 33 | useEffect(() => { |
24 | 34 | const container = containerRef.current; |
@@ -64,8 +74,81 @@ export default function HeroBackdropVideo({ onReady }: Props) { |
64 | 74 | }; |
65 | 75 | }, [isVisible]); |
66 | 76 |
|
| 77 | + useEffect(() => { |
| 78 | + if (hasInteracted) return; |
| 79 | + |
| 80 | + const handleInteraction = () => setHasInteracted(true); |
| 81 | + const options = { once: true, passive: true }; |
| 82 | + |
| 83 | + window.addEventListener("pointerdown", handleInteraction, options); |
| 84 | + window.addEventListener("keydown", handleInteraction, { once: true }); |
| 85 | + window.addEventListener("touchstart", handleInteraction, options); |
| 86 | + |
| 87 | + return () => { |
| 88 | + window.removeEventListener("pointerdown", handleInteraction); |
| 89 | + window.removeEventListener("keydown", handleInteraction); |
| 90 | + window.removeEventListener("touchstart", handleInteraction); |
| 91 | + }; |
| 92 | + }, [hasInteracted]); |
| 93 | + |
| 94 | + useEffect(() => { |
| 95 | + if (!isYouTubeEngaged) return; |
| 96 | + onYouTubeEngaged?.(); |
| 97 | + }, [isYouTubeEngaged, onYouTubeEngaged]); |
| 98 | + |
| 99 | + const handleYouTubeReady = () => { |
| 100 | + setIsYouTubeReady(true); |
| 101 | + onReady?.(); |
| 102 | + }; |
| 103 | + |
67 | 104 | if (!video) return <div ref={containerRef} className="absolute inset-0" aria-hidden="true" />; |
68 | 105 |
|
| 106 | + if (video.kind === "youtube") { |
| 107 | + return ( |
| 108 | + <div ref={containerRef} className="absolute inset-0 overflow-hidden bg-black" aria-hidden="true"> |
| 109 | + <div |
| 110 | + className={`absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 transition-[filter,transform] duration-1000 ease-out will-change-transform ${ |
| 111 | + isYouTubeEngaged |
| 112 | + ? "scale-[1.04] brightness-[1.1] contrast-[1.08] saturate-[1.15]" |
| 113 | + : "scale-100 brightness-[0.9] saturate-[0.9]" |
| 114 | + }`} |
| 115 | + style={{ |
| 116 | + width: "max(100%, 177.777778vh)", |
| 117 | + height: "max(100%, 56.25vw)", |
| 118 | + }} |
| 119 | + > |
| 120 | + <ReactPlayer |
| 121 | + url={video.url} |
| 122 | + playing |
| 123 | + loop |
| 124 | + muted={!hasInteracted || !isYouTubeReady} |
| 125 | + controls={false} |
| 126 | + playsinline |
| 127 | + width="100%" |
| 128 | + height="100%" |
| 129 | + onReady={handleYouTubeReady} |
| 130 | + config={{ |
| 131 | + youtube: { |
| 132 | + playerVars: { |
| 133 | + autoplay: 1, |
| 134 | + controls: 0, |
| 135 | + disablekb: 1, |
| 136 | + fs: 0, |
| 137 | + iv_load_policy: 3, |
| 138 | + loop: 1, |
| 139 | + modestbranding: 1, |
| 140 | + playsinline: 1, |
| 141 | + playlist: video.id, |
| 142 | + rel: 0, |
| 143 | + }, |
| 144 | + }, |
| 145 | + }} |
| 146 | + /> |
| 147 | + </div> |
| 148 | + </div> |
| 149 | + ); |
| 150 | + } |
| 151 | + |
69 | 152 | return ( |
70 | 153 | <div ref={containerRef} className="absolute inset-0" aria-hidden="true"> |
71 | 154 | <video |
|
0 commit comments