File size: 1,833 Bytes
b96b3a8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | import React, { ReactNode, useEffect, useRef, useState } from 'react';
interface PanelContainerProps {
title: string;
children: ReactNode;
description: string;
panelNumber: number;
}
const PanelContainer: React.FC<PanelContainerProps> = ({
title,
children,
description,
panelNumber
}) => {
const [isVisible, setIsVisible] = useState(false);
const panelRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
}
},
{
root: null,
rootMargin: '0px',
threshold: 0.3,
}
);
if (panelRef.current) {
observer.observe(panelRef.current);
}
return () => {
if (panelRef.current) {
observer.unobserve(panelRef.current);
}
};
}, []);
return (
<section
ref={panelRef}
className={`min-h-screen py-16 px-4 md:px-8 flex flex-col justify-center transition-opacity duration-1000 ease-in-out ${
isVisible ? 'opacity-100' : 'opacity-0'
}`}
>
<div className="relative">
<div className="absolute -left-16 top-2 hidden md:flex items-center justify-center w-12 h-12 rounded-full bg-gradient-to-r from-blue-600 to-purple-600 text-white font-bold text-xl">
{panelNumber}
</div>
</div>
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-blue-500">
{title}
</h2>
<p className="mb-8 text-gray-300 max-w-2xl">{description}</p>
<div className="bg-gray-800 border border-gray-700 rounded-xl p-6 shadow-lg shadow-purple-900/10">
{children}
</div>
</section>
);
};
export default PanelContainer; |