feat: hero diagonal split with 3 dancer videos
- Three video panels with diagonal clip-paths and gold separator lines - Each video centered in its own column for clear visibility - Replaced nastya.mp4 with nastya-2.mp4 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,8 @@ import { FloatingHearts } from "@/components/ui/FloatingHearts";
|
||||
import { HeroLogo } from "@/components/ui/HeroLogo";
|
||||
import type { SiteContent } from "@/types/content";
|
||||
|
||||
const VIDEOS = ["/video/ira.mp4", "/video/nadezda.mp4", "/video/nastya-2.mp4"];
|
||||
|
||||
interface HeroProps {
|
||||
data: SiteContent["hero"];
|
||||
}
|
||||
@@ -15,10 +17,9 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
const scrolledRef = useRef(false);
|
||||
|
||||
const scrollToNext = useCallback(() => {
|
||||
const hero = sectionRef.current;
|
||||
if (!hero) return;
|
||||
// Find the next sibling section
|
||||
let next = hero.nextElementSibling;
|
||||
const el = sectionRef.current;
|
||||
if (!el) return;
|
||||
let next = el.nextElementSibling;
|
||||
while (next && next.tagName !== "SECTION") {
|
||||
next = next.nextElementSibling;
|
||||
}
|
||||
@@ -26,76 +27,82 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const hero = sectionRef.current;
|
||||
if (!hero) return;
|
||||
const el = sectionRef.current;
|
||||
if (!el) return;
|
||||
|
||||
function handleWheel(e: WheelEvent) {
|
||||
// Only trigger when scrolling down and still inside hero
|
||||
if (e.deltaY <= 0 || scrolledRef.current) return;
|
||||
if (window.scrollY > 10) return; // already scrolled past hero top
|
||||
|
||||
if (window.scrollY > 10) return;
|
||||
scrolledRef.current = true;
|
||||
scrollToNext();
|
||||
|
||||
// Reset after animation completes
|
||||
setTimeout(() => { scrolledRef.current = false; }, 1000);
|
||||
}
|
||||
|
||||
function handleTouchStart(e: TouchEvent) {
|
||||
(hero as HTMLElement).dataset.touchY = String(e.touches[0].clientY);
|
||||
(el as HTMLElement).dataset.touchY = String(e.touches[0].clientY);
|
||||
}
|
||||
|
||||
function handleTouchEnd(e: TouchEvent) {
|
||||
const startY = Number((hero as HTMLElement).dataset.touchY);
|
||||
const startY = Number((el as HTMLElement).dataset.touchY);
|
||||
const endY = e.changedTouches[0].clientY;
|
||||
const diff = startY - endY;
|
||||
|
||||
// Swipe down (finger moves up) with enough distance
|
||||
if (diff > 50 && !scrolledRef.current && window.scrollY < 10) {
|
||||
if (startY - endY > 50 && !scrolledRef.current && window.scrollY < 10) {
|
||||
scrolledRef.current = true;
|
||||
scrollToNext();
|
||||
setTimeout(() => { scrolledRef.current = false; }, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
hero.addEventListener("wheel", handleWheel, { passive: true });
|
||||
hero.addEventListener("touchstart", handleTouchStart, { passive: true });
|
||||
hero.addEventListener("touchend", handleTouchEnd, { passive: true });
|
||||
el.addEventListener("wheel", handleWheel, { passive: true });
|
||||
el.addEventListener("touchstart", handleTouchStart, { passive: true });
|
||||
el.addEventListener("touchend", handleTouchEnd, { passive: true });
|
||||
return () => {
|
||||
hero.removeEventListener("wheel", handleWheel);
|
||||
hero.removeEventListener("touchstart", handleTouchStart);
|
||||
hero.removeEventListener("touchend", handleTouchEnd);
|
||||
el.removeEventListener("wheel", handleWheel);
|
||||
el.removeEventListener("touchstart", handleTouchStart);
|
||||
el.removeEventListener("touchend", handleTouchEnd);
|
||||
};
|
||||
}, [scrollToNext]);
|
||||
|
||||
return (
|
||||
<section ref={sectionRef} className="relative flex min-h-svh items-center justify-center overflow-hidden bg-[#050505]">
|
||||
{/* Animated gradient background */}
|
||||
<div className="hero-bg-gradient absolute inset-0" />
|
||||
|
||||
{/* Glow orbs */}
|
||||
{/* Diagonal split background — 3 dancer videos */}
|
||||
<div className="absolute inset-0">
|
||||
{VIDEOS.map((src, i) => {
|
||||
const positions = [
|
||||
{ left: "0%", width: "38%" },
|
||||
{ left: "31%", width: "38%" },
|
||||
{ left: "62%", width: "38%" },
|
||||
];
|
||||
const clips = [
|
||||
"polygon(0 0, 100% 0, 86% 100%, 0 100%)",
|
||||
"polygon(14% 0, 100% 0, 86% 100%, 0 100%)",
|
||||
"polygon(14% 0, 100% 0, 100% 100%, 0 100%)",
|
||||
];
|
||||
return (
|
||||
<div
|
||||
className="hero-glow-orb"
|
||||
key={src}
|
||||
className="absolute top-0 bottom-0 overflow-hidden"
|
||||
style={{
|
||||
width: "500px",
|
||||
height: "500px",
|
||||
top: "-10%",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
background: "radial-gradient(circle, rgba(201, 169, 110, 0.12), transparent 70%)",
|
||||
left: positions[i].left,
|
||||
width: positions[i].width,
|
||||
clipPath: clips[i],
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="hero-glow-orb"
|
||||
style={{
|
||||
width: "300px",
|
||||
height: "300px",
|
||||
bottom: "10%",
|
||||
right: "10%",
|
||||
background: "radial-gradient(circle, rgba(201, 169, 110, 0.08), transparent 70%)",
|
||||
animationDelay: "3s",
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<video
|
||||
autoPlay muted loop playsInline
|
||||
className="absolute inset-0 h-full w-full object-cover object-center"
|
||||
>
|
||||
<source src={src} type="video/mp4" />
|
||||
</video>
|
||||
<div className="absolute inset-0 bg-black/50" />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{/* Gold diagonal lines between panels */}
|
||||
<svg className="absolute inset-0 h-full w-full z-10 pointer-events-none" preserveAspectRatio="none" viewBox="0 0 100 100">
|
||||
<line x1="38" y1="0" x2="33" y2="100" stroke="rgba(201,169,110,0.25)" strokeWidth="0.15" />
|
||||
<line x1="69" y1="0" x2="64" y2="100" stroke="rgba(201,169,110,0.25)" strokeWidth="0.15" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Floating hearts */}
|
||||
<FloatingHearts />
|
||||
@@ -103,7 +110,6 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
{/* Content */}
|
||||
<div className="section-container relative z-10 text-center">
|
||||
<div className="hero-logo relative mx-auto mb-10 flex items-center justify-center" style={{ width: 220, height: 181 }}>
|
||||
{/* Soft ambient glow behind heart */}
|
||||
<div className="absolute -inset-10 rounded-full blur-[80px]" style={{ background: "radial-gradient(circle, rgba(201,169,110,0.25), transparent 70%)" }} />
|
||||
<div className="hero-logo-heartbeat relative">
|
||||
<HeroLogo
|
||||
@@ -127,7 +133,6 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user