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";
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useRef, useCallback } from "react";
|
||||||
import { Button } from "@/components/ui/Button";
|
import { Button } from "@/components/ui/Button";
|
||||||
import { FloatingHearts } from "@/components/ui/FloatingHearts";
|
import { FloatingHearts } from "@/components/ui/FloatingHearts";
|
||||||
import { HeroLogo } from "@/components/ui/HeroLogo";
|
import { HeroLogo } from "@/components/ui/HeroLogo";
|
||||||
import { ChevronDown } from "lucide-react";
|
|
||||||
import type { SiteContent } from "@/types/content";
|
import type { SiteContent } from "@/types/content";
|
||||||
|
|
||||||
interface HeroProps {
|
interface HeroProps {
|
||||||
@@ -11,9 +11,65 @@ interface HeroProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Hero({ data: hero }: 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 (
|
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 */}
|
{/* Animated gradient background */}
|
||||||
<div className="hero-bg-gradient absolute inset-0" />
|
<div className="hero-bg-gradient absolute inset-0" />
|
||||||
|
|
||||||
@@ -72,16 +128,6 @@ export function Hero({ data: hero }: HeroProps) {
|
|||||||
</div>
|
</div>
|
||||||
</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>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user