| 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; |