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