- Created complete Next.js 15 teaser website with CHORUS brand styling - Implemented mobile-responsive 3D logo (128px mobile, 512px desktop) - Added proper Exo font loading via Next.js Google Fonts for iOS/Chrome compatibility - Built comprehensive early access form with GDPR compliance and rate limiting - Integrated PostgreSQL database with complete schema for lead capture - Added scroll indicators that auto-hide when scrolling begins - Optimized mobile modal forms with proper scrolling and submit button access - Deployed via Docker Swarm with Traefik SSL termination at chorus.services - Includes database migrations, consent tracking, and email notifications 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
62 lines
1.5 KiB
TypeScript
62 lines
1.5 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver';
|
|
|
|
interface ScrollRevealProps {
|
|
children: React.ReactNode;
|
|
delay?: number;
|
|
duration?: number;
|
|
direction?: 'up' | 'down' | 'left' | 'right';
|
|
distance?: number;
|
|
className?: string;
|
|
}
|
|
|
|
export default function ScrollReveal({
|
|
children,
|
|
delay = 0,
|
|
duration = 600,
|
|
direction = 'up',
|
|
distance = 24,
|
|
className = '',
|
|
}: ScrollRevealProps) {
|
|
const { elementRef, isVisible } = useIntersectionObserver({
|
|
threshold: 0.1,
|
|
rootMargin: '0px 0px -100px 0px',
|
|
triggerOnce: true,
|
|
});
|
|
|
|
const getTransform = (visible: boolean) => {
|
|
if (visible) return 'translate3d(0, 0, 0)';
|
|
|
|
switch (direction) {
|
|
case 'up':
|
|
return `translate3d(0, ${distance}px, 0)`;
|
|
case 'down':
|
|
return `translate3d(0, -${distance}px, 0)`;
|
|
case 'left':
|
|
return `translate3d(${distance}px, 0, 0)`;
|
|
case 'right':
|
|
return `translate3d(-${distance}px, 0, 0)`;
|
|
default:
|
|
return `translate3d(0, ${distance}px, 0)`;
|
|
}
|
|
};
|
|
|
|
const revealStyle = {
|
|
opacity: isVisible ? 1 : 0,
|
|
transform: getTransform(isVisible),
|
|
transition: `opacity ${duration}ms ease-out ${delay}ms, transform ${duration}ms ease-out ${delay}ms`,
|
|
willChange: 'opacity, transform',
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={elementRef}
|
|
style={revealStyle}
|
|
className={`scroll-reveal ${className}`}
|
|
>
|
|
{children}
|
|
</div>
|
|
);
|
|
} |