feat: remove scroll indicator, add auto-scroll from hero to next section
- Remove SCROLL chevron button from hero (not needed) - Add wheel/swipe listener that smoothly scrolls to the first section below hero - Works on desktop (wheel) and mobile (touch swipe) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useCallback } from "react";
|
||||
import { Button } from "@/components/ui/Button";
|
||||
import { FloatingHearts } from "@/components/ui/FloatingHearts";
|
||||
import { HeroLogo } from "@/components/ui/HeroLogo";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import type { SiteContent } from "@/types/content";
|
||||
|
||||
interface HeroProps {
|
||||
@@ -11,9 +11,65 @@ interface HeroProps {
|
||||
}
|
||||
|
||||
export function Hero({ data: hero }: HeroProps) {
|
||||
const sectionRef = useRef<HTMLElement>(null);
|
||||
const scrolledRef = useRef(false);
|
||||
|
||||
const scrollToNext = useCallback(() => {
|
||||
const hero = sectionRef.current;
|
||||
if (!hero) return;
|
||||
// Find the next sibling section
|
||||
let next = hero.nextElementSibling;
|
||||
while (next && next.tagName !== "SECTION") {
|
||||
next = next.nextElementSibling;
|
||||
}
|
||||
next?.scrollIntoView({ behavior: "smooth" });
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const hero = sectionRef.current;
|
||||
if (!hero) 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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function handleTouchEnd(e: TouchEvent) {
|
||||
const startY = Number((hero 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) {
|
||||
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 });
|
||||
return () => {
|
||||
hero.removeEventListener("wheel", handleWheel);
|
||||
hero.removeEventListener("touchstart", handleTouchStart);
|
||||
hero.removeEventListener("touchend", handleTouchEnd);
|
||||
};
|
||||
}, [scrollToNext]);
|
||||
|
||||
return (
|
||||
<section className="relative flex min-h-svh items-center justify-center overflow-hidden bg-[#050505]">
|
||||
<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" />
|
||||
|
||||
@@ -72,16 +128,6 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scroll indicator */}
|
||||
<div className="hero-cta absolute bottom-8 left-1/2 -translate-x-1/2">
|
||||
<a
|
||||
href="#about"
|
||||
className="flex flex-col items-center gap-1 text-neutral-600 transition-colors hover:text-gold-light"
|
||||
>
|
||||
<span className="text-xs uppercase tracking-widest">Scroll</span>
|
||||
<ChevronDown size={20} className="animate-bounce" />
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user