Skip to content

Commit 671920c

Browse files
authored
Merge pull request #404 from ACM-VIT/dev
Dev
2 parents b2a3b08 + 3646c61 commit 671920c

4 files changed

Lines changed: 133 additions & 10 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY
2+
version = 1
3+
name = "ExamCooker-2024"
4+
5+
[setup]
6+
script = ""
7+
8+
[[actions]]
9+
name = "Run"
10+
icon = "run"
11+
command = "pnpm dev"

app/(app)/home/course-search.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ export default function CourseSearch({ courses }: CourseSearchProps) {
301301
) : (
302302
<input
303303
ref={inputRef}
304-
type="search"
304+
type="text"
305305
inputMode="search"
306306
enterKeyHint="search"
307307
autoCapitalize="off"

app/(app)/home/hero-backdrop-video.tsx

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,34 @@
11
"use client";
22

33
import { useEffect, useRef, useState } from "react";
4+
import ReactPlayer from "react-player";
45
import { scheduleIdleWork } from "@/lib/schedule-idle-work";
56

67
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+
},
1117
] as const;
1218
const TABLET_MIN_WIDTH_MEDIA = "(min-width: 600px)";
1319

1420
interface Props {
1521
onReady?: () => void;
22+
onYouTubeEngaged?: () => void;
1623
}
1724

18-
export default function HeroBackdropVideo({ onReady }: Props) {
25+
export default function HeroBackdropVideo({ onReady, onYouTubeEngaged }: Props) {
1926
const containerRef = useRef<HTMLDivElement | null>(null);
2027
const [isVisible, setIsVisible] = useState(false);
2128
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;
2232

2333
useEffect(() => {
2434
const container = containerRef.current;
@@ -64,8 +74,81 @@ export default function HeroBackdropVideo({ onReady }: Props) {
6474
};
6575
}, [isVisible]);
6676

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+
67104
if (!video) return <div ref={containerRef} className="absolute inset-0" aria-hidden="true" />;
68105

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+
69152
return (
70153
<div ref={containerRef} className="absolute inset-0" aria-hidden="true">
71154
<video

app/(app)/home/hero-frame.tsx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"use client";
22

3-
import { ReactNode, useState } from "react";
3+
import { ReactNode, useCallback, useState } from "react";
44
import HeroBackdropVideo from "./hero-backdrop-video";
55

66
export default function HeroFrame({ children }: { children: ReactNode }) {
77
const [videoReady, setVideoReady] = useState(false);
8+
const [youtubeEngaged, setYoutubeEngaged] = useState(false);
9+
const handleBackdropReady = useCallback(() => setVideoReady(true), []);
10+
const handleYouTubeEngaged = useCallback(() => setYoutubeEngaged(true), []);
811

912
return (
1013
<div
@@ -16,14 +19,40 @@ export default function HeroFrame({ children }: { children: ReactNode }) {
1619
aria-hidden="true"
1720
className="pointer-events-none absolute inset-0 z-0 hidden overflow-hidden min-[600px]:block"
1821
>
19-
<HeroBackdropVideo onReady={() => setVideoReady(true)} />
20-
<div className="absolute inset-0 bg-[#C2E6EC]/10 dark:bg-[hsl(224,48%,9%)]/45" />
22+
<HeroBackdropVideo
23+
onReady={handleBackdropReady}
24+
onYouTubeEngaged={handleYouTubeEngaged}
25+
/>
26+
<div
27+
className={`absolute inset-0 transition-colors duration-700 ${
28+
youtubeEngaged
29+
? "bg-black/5 dark:bg-black/10"
30+
: "bg-[#C2E6EC]/10 dark:bg-[hsl(224,48%,9%)]/45"
31+
}`}
32+
/>
33+
<div
34+
className={`absolute inset-0 transition-opacity duration-1000 ${
35+
youtubeEngaged ? "opacity-100" : "opacity-0"
36+
}`}
37+
style={{
38+
background:
39+
"radial-gradient(circle at center, transparent 0%, transparent 46%, rgba(0, 0, 0, 0.58) 100%)",
40+
}}
41+
/>
2142
<div className="absolute inset-x-0 top-0 hidden h-32 bg-gradient-to-b to-transparent dark:block dark:from-[hsl(224,48%,9%)]" />
2243
<div className="absolute inset-x-0 bottom-0 hidden h-32 bg-gradient-to-t to-transparent dark:block dark:from-[hsl(224,48%,9%)]" />
2344
<div className="absolute inset-y-0 left-0 hidden w-32 bg-gradient-to-r to-transparent dark:block dark:from-[hsl(224,48%,9%)]" />
2445
<div className="absolute inset-y-0 right-0 hidden w-32 bg-gradient-to-l to-transparent dark:block dark:from-[hsl(224,48%,9%)]" />
2546
</div>
26-
{children}
47+
<div
48+
className={`relative z-10 transition-opacity duration-700 ease-out ${
49+
youtubeEngaged
50+
? "min-[600px]:opacity-[0.5] min-[600px]:hover:opacity-100 min-[600px]:focus-within:opacity-100"
51+
: ""
52+
}`}
53+
>
54+
{children}
55+
</div>
2756
</div>
2857
);
2958
}

0 commit comments

Comments
 (0)