304 lines
11 KiB
TypeScript
304 lines
11 KiB
TypeScript
|
|
import React, { useState, useEffect, useCallback } from 'react';
|
||
|
|
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||
|
|
import { navigateTo } from './Router';
|
||
|
|
import svgPaths from "../imports/svg-i1joeov37f";
|
||
|
|
|
||
|
|
interface SlideData {
|
||
|
|
id: number;
|
||
|
|
title: string;
|
||
|
|
description: string;
|
||
|
|
backgroundImage: string;
|
||
|
|
shortTitle: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function HeroSection() {
|
||
|
|
const [currentSlide, setCurrentSlide] = useState(0);
|
||
|
|
const [isAutoPlaying, setIsAutoPlaying] = useState(true);
|
||
|
|
const [progressValues, setProgressValues] = useState([0, 0, 0]);
|
||
|
|
|
||
|
|
const slides: SlideData[] = [
|
||
|
|
{
|
||
|
|
id: 1,
|
||
|
|
title: "Empowering Future-Ready\nLeaders",
|
||
|
|
description: "Build confidence, agility, and clarity for today's complex challenges.",
|
||
|
|
backgroundImage: "https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1920&q=80",
|
||
|
|
shortTitle: "Leadership Is Learned. We Teach It Right."
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 2,
|
||
|
|
title: "Turn Managers into\nImpactful Leaders",
|
||
|
|
description: "Transform your management team into visionary leaders who inspire teams, drive innovation, and achieve exceptional business outcomes.",
|
||
|
|
backgroundImage: "https://images.unsplash.com/photo-1600880292203-757bb62b4baf?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1920&q=80",
|
||
|
|
shortTitle: "Turn Managers into Impactful Leaders"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 3,
|
||
|
|
title: "Struggling with\nManagerial Gaps?",
|
||
|
|
description: "Bridge the leadership gap in your organization with our proven methodologies that develop confident, capable leaders at every level.",
|
||
|
|
backgroundImage: "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1920&q=80",
|
||
|
|
shortTitle: "Struggling with Managerial Gaps?"
|
||
|
|
}
|
||
|
|
];
|
||
|
|
|
||
|
|
const totalSlides = slides.length;
|
||
|
|
const slideDuration = 5000; // 5 seconds per slide
|
||
|
|
|
||
|
|
// Auto-advance slides
|
||
|
|
useEffect(() => {
|
||
|
|
if (!isAutoPlaying) return;
|
||
|
|
|
||
|
|
const interval = setInterval(() => {
|
||
|
|
setCurrentSlide((prev) => (prev + 1) % totalSlides);
|
||
|
|
}, slideDuration);
|
||
|
|
|
||
|
|
return () => clearInterval(interval);
|
||
|
|
}, [isAutoPlaying, totalSlides]);
|
||
|
|
|
||
|
|
// Progress bar animation
|
||
|
|
useEffect(() => {
|
||
|
|
if (!isAutoPlaying) return;
|
||
|
|
|
||
|
|
const interval = setInterval(() => {
|
||
|
|
setProgressValues(prev => {
|
||
|
|
const newProgress = [...prev];
|
||
|
|
newProgress[currentSlide] = Math.min(newProgress[currentSlide] + (100 / (slideDuration / 100)), 100);
|
||
|
|
// Reset progress when slide changes
|
||
|
|
if (newProgress[currentSlide] >= 100) {
|
||
|
|
newProgress[currentSlide] = 0;
|
||
|
|
// Reset other slides
|
||
|
|
newProgress.forEach((_, index) => {
|
||
|
|
if (index !== currentSlide) {
|
||
|
|
newProgress[index] = 0;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return newProgress;
|
||
|
|
});
|
||
|
|
}, 100);
|
||
|
|
|
||
|
|
return () => clearInterval(interval);
|
||
|
|
}, [currentSlide, isAutoPlaying]);
|
||
|
|
|
||
|
|
// Reset progress when manually changing slides
|
||
|
|
useEffect(() => {
|
||
|
|
setProgressValues(prev => {
|
||
|
|
const newProgress = [0, 0, 0];
|
||
|
|
newProgress[currentSlide] = 0;
|
||
|
|
return newProgress;
|
||
|
|
});
|
||
|
|
}, [currentSlide]);
|
||
|
|
|
||
|
|
const goToSlide = useCallback((slideIndex: number) => {
|
||
|
|
if (slideIndex !== currentSlide) {
|
||
|
|
setCurrentSlide(slideIndex);
|
||
|
|
setIsAutoPlaying(false);
|
||
|
|
// Resume auto-play after manual interaction
|
||
|
|
setTimeout(() => setIsAutoPlaying(true), 3000);
|
||
|
|
}
|
||
|
|
}, [currentSlide]);
|
||
|
|
|
||
|
|
const nextSlide = useCallback(() => {
|
||
|
|
const next = (currentSlide + 1) % totalSlides;
|
||
|
|
goToSlide(next);
|
||
|
|
}, [currentSlide, totalSlides, goToSlide]);
|
||
|
|
|
||
|
|
const prevSlide = useCallback(() => {
|
||
|
|
const prev = (currentSlide - 1 + totalSlides) % totalSlides;
|
||
|
|
goToSlide(prev);
|
||
|
|
}, [currentSlide, totalSlides, goToSlide]);
|
||
|
|
|
||
|
|
// Pause auto-play on hover
|
||
|
|
const handleMouseEnter = () => setIsAutoPlaying(false);
|
||
|
|
const handleMouseLeave = () => setIsAutoPlaying(true);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<section
|
||
|
|
className="hero-section"
|
||
|
|
onMouseEnter={handleMouseEnter}
|
||
|
|
onMouseLeave={handleMouseLeave}
|
||
|
|
>
|
||
|
|
{/* Background Slides */}
|
||
|
|
{slides.map((slide, index) => (
|
||
|
|
<div
|
||
|
|
key={slide.id}
|
||
|
|
className={`hero-slide ${index === currentSlide ? 'active' : ''}`}
|
||
|
|
style={{
|
||
|
|
backgroundImage: `url('${slide.backgroundImage}')`
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<div className="hero-overlay" />
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
|
||
|
|
{/* Hero Content */}
|
||
|
|
<div className="hero-content">
|
||
|
|
<div className="hero-text-section">
|
||
|
|
{/* Title */}
|
||
|
|
<h1 className="hero-title" style={{ whiteSpace: 'pre-line' }}>
|
||
|
|
{slides[currentSlide].title}
|
||
|
|
</h1>
|
||
|
|
{/* Description */}
|
||
|
|
<p className="hero-description">
|
||
|
|
{slides[currentSlide].description}
|
||
|
|
</p>
|
||
|
|
|
||
|
|
{/* Build Your Leadership Pipeline Button - Enhanced with Proper Navigation */}
|
||
|
|
<button
|
||
|
|
className="hero-slide-button group box-border content-stretch flex flex-row gap-2.5 items-center justify-start p-0 relative cursor-pointer overflow-hidden"
|
||
|
|
style={{
|
||
|
|
background: 'transparent',
|
||
|
|
border: 'none'
|
||
|
|
}}
|
||
|
|
onClick={() => {
|
||
|
|
console.log('Hero button clicked - navigating to contact page');
|
||
|
|
navigateTo('/contact?topic=leadership-pipeline');
|
||
|
|
}}
|
||
|
|
aria-label="Build Your Leadership Pipeline"
|
||
|
|
>
|
||
|
|
{/* Icon Container with Slide Animation */}
|
||
|
|
<div className="relative shrink-0 size-[50px] overflow-hidden">
|
||
|
|
{/* Background Rectangle - Consistent Blue Color */}
|
||
|
|
<div className="absolute inset-0 bg-[#04045B]" />
|
||
|
|
|
||
|
|
{/* Icon Layer - Sliding Animation */}
|
||
|
|
<div className="icon-layer absolute inset-0 w-full h-full">
|
||
|
|
{/* Primary Arrow - Slides out diagonally up-right */}
|
||
|
|
<div className="icon absolute inset-0 flex items-center justify-center transition-all duration-300 ease-in-out group-hover:translate-x-6 group-hover:-translate-y-6 group-hover:opacity-0">
|
||
|
|
<svg
|
||
|
|
className="block w-full h-full"
|
||
|
|
fill="none"
|
||
|
|
preserveAspectRatio="none"
|
||
|
|
viewBox="0 0 50 50"
|
||
|
|
>
|
||
|
|
<g clipPath="url(#clip0_95_1043_primary)">
|
||
|
|
<path d={svgPaths.p5b8d700} fill="white" />
|
||
|
|
<path d={svgPaths.p30b71a00} fill="white" />
|
||
|
|
</g>
|
||
|
|
<defs>
|
||
|
|
<clipPath id="clip0_95_1043_primary">
|
||
|
|
<rect fill="white" height="50" width="50" />
|
||
|
|
</clipPath>
|
||
|
|
</defs>
|
||
|
|
</svg>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Secondary Arrow - Slides in from bottom-left */}
|
||
|
|
<div className="icon absolute inset-0 flex items-center justify-center opacity-0 -translate-x-6 translate-y-6 transition-all duration-300 ease-in-out group-hover:translate-x-0 group-hover:translate-y-0 group-hover:opacity-100">
|
||
|
|
<svg
|
||
|
|
className="block w-full h-full"
|
||
|
|
fill="none"
|
||
|
|
preserveAspectRatio="none"
|
||
|
|
viewBox="0 0 50 50"
|
||
|
|
>
|
||
|
|
<g clipPath="url(#clip0_95_1043_secondary)">
|
||
|
|
<path d={svgPaths.p5b8d700} fill="white" />
|
||
|
|
<path d={svgPaths.p30b71a00} fill="white" />
|
||
|
|
</g>
|
||
|
|
<defs>
|
||
|
|
<clipPath id="clip0_95_1043_secondary">
|
||
|
|
<rect fill="white" height="50" width="50" />
|
||
|
|
</clipPath>
|
||
|
|
</defs>
|
||
|
|
</svg>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Text Section with Vertical Slide Animation */}
|
||
|
|
<div className="text-layer relative shrink-0 overflow-hidden flex items-center" style={{
|
||
|
|
height: '28px',
|
||
|
|
fontFamily: 'Inter, sans-serif',
|
||
|
|
fontSize: '20px',
|
||
|
|
fontWeight: '400',
|
||
|
|
lineHeight: '28px',
|
||
|
|
whiteSpace: 'nowrap',
|
||
|
|
color: '#ffffff'
|
||
|
|
}}>
|
||
|
|
{/* Primary Text - Slides up and out */}
|
||
|
|
<div
|
||
|
|
className="text-element absolute inset-0 flex items-center justify-start transition-all duration-300 ease-in-out group-hover:-translate-y-full group-hover:opacity-0"
|
||
|
|
style={{
|
||
|
|
color: '#ffffff !important',
|
||
|
|
textShadow: '0 1px 2px rgba(0, 0, 0, 0.4)',
|
||
|
|
fontFamily: 'Inter, sans-serif',
|
||
|
|
fontSize: '20px',
|
||
|
|
fontWeight: '400',
|
||
|
|
lineHeight: '28px'
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
Build Your Leadership Pipeline
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Secondary Text - Slides in from bottom */}
|
||
|
|
<div
|
||
|
|
className="text-element absolute inset-0 flex items-center justify-start translate-y-full opacity-0 transition-all duration-300 ease-in-out group-hover:translate-y-0 group-hover:opacity-100"
|
||
|
|
style={{
|
||
|
|
color: '#ffffff !important',
|
||
|
|
textShadow: '0 1px 2px rgba(0, 0, 0, 0.4)',
|
||
|
|
fontFamily: 'Inter, sans-serif',
|
||
|
|
fontSize: '20px',
|
||
|
|
fontWeight: '400',
|
||
|
|
lineHeight: '28px'
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
Build Your Leadership Pipeline
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Bottom Navigation */}
|
||
|
|
<div className="hero-navigation">
|
||
|
|
{/* Progress Section */}
|
||
|
|
<div className="hero-progress-container">
|
||
|
|
{slides.map((slide, index) => (
|
||
|
|
<div
|
||
|
|
key={slide.id}
|
||
|
|
className="hero-progress-item"
|
||
|
|
onClick={() => goToSlide(index)}
|
||
|
|
>
|
||
|
|
{/* Progress Bar */}
|
||
|
|
<div
|
||
|
|
className={`hero-progress-segment ${index === currentSlide ? 'active' : ''}`}
|
||
|
|
>
|
||
|
|
<div
|
||
|
|
className="hero-progress-fill"
|
||
|
|
style={{ width: index === currentSlide ? `${progressValues[index]}%` : '0%' }}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Progress Number */}
|
||
|
|
<div className={`hero-progress-number ${index === currentSlide ? 'active' : ''}`}>
|
||
|
|
{String(index + 1).padStart(2, '0')}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Progress Text */}
|
||
|
|
<div className={`hero-progress-text ${index === currentSlide ? 'active' : ''}`}>
|
||
|
|
{slide.shortTitle}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Navigation Arrows */}
|
||
|
|
<div className="hero-controls">
|
||
|
|
<button
|
||
|
|
className="hero-nav-button"
|
||
|
|
onClick={prevSlide}
|
||
|
|
aria-label="Previous slide"
|
||
|
|
>
|
||
|
|
<ChevronLeft className="w-5 h-5" />
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
className="hero-nav-button"
|
||
|
|
onClick={nextSlide}
|
||
|
|
aria-label="Next slide"
|
||
|
|
>
|
||
|
|
<ChevronRight className="w-5 h-5" />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
);
|
||
|
|
}
|