Files
KLC-Website-Frontend/src/components/HeroSection.tsx

314 lines
12 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;
backgroundImage: string;
shortTitle: string;
ctaText: string;
}
export default function HeroSection() {
const [currentSlide, setCurrentSlide] = useState(0);
const [isAutoPlaying, setIsAutoPlaying] = useState(true);
const [progressValues, setProgressValues] = useState([0, 0, 0, 0, 0]);
const slides: SlideData[] = [
{
id: 1,
title: "Build Leaders Who Drive Business Growth",
backgroundImage: "https://images.unsplash.com/photo-1705234384669-c6d31c61b789?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxleGVjdXRpdmUlMjBsZWFkZXJzaGlwJTIwZGV2ZWxvcG1lbnQlMjB0cmFpbmluZ3xlbnwxfHx8fDE3NTY4MDcyNjJ8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
shortTitle: "Leadership Development Programs",
ctaText: "Explore Leadership Journeys"
},
{
id: 2,
title: "Strengthen the Backbone: Your Managers",
backgroundImage: "https://images.unsplash.com/photo-1565688527174-775059ac429c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtYW5hZ2VtZW50JTIwdGVhbSUyMGRpc2N1c3Npb24lMjBvZmZpY2V8ZW58MXx8fHwxNzU2ODA2ODg1fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
shortTitle: "Management Development Programs",
ctaText: "Strengthen your Managerial Calibre"
},
{
id: 3,
title: "Shape Cultures That Accelerate Performance",
backgroundImage: "https://images.unsplash.com/photo-1531535807748-218331acbcb4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxjb3Jwb3JhdGUlMjBjdWx0dXJlJTIwdGVhbSUyMGNvbGxhYm9yYXRpb258ZW58MXx8fHwxNzU2ODA2ODg5fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
shortTitle: "Culture & Competence Consulting",
ctaText: "Learn how we facilitate Change"
},
{
id: 4,
title: "Unlock Leadership Potential",
backgroundImage: "https://images.unsplash.com/photo-1714974528833-a10e19a8f951?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxleGVjdXRpdmUlMjBjb2FjaGluZyUyMG1lbnRvciUyMGNvbnZlcnNhdGlvbnxlbnwxfHx8fDE3NTY4MDY4OTR8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
shortTitle: "Coaching & Mentoring",
ctaText: "Start a Coaching Conversation"
},
{
id: 5,
title: "Know Your Leaders. Strengthen Your Pipeline.",
backgroundImage: "https://images.unsplash.com/photo-1697059361419-349e924ed363?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxidXNpbmVzcyUyMGxlYWRlcnMlMjBzdHJhdGVneSUyMG1lZXRpbmd8ZW58MXx8fHwxNzU2ODA3Mjc0fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
shortTitle: "Assessments & Leadership Pipeline",
ctaText: "Discover Our Assessment Solutions"
}
];
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, 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>
{/* Dynamic CTA 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={slides[currentSlide].ctaText}
>
{/* 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'
}}
>
{slides[currentSlide].ctaText}
</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'
}}
>
{slides[currentSlide].ctaText}
</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>
);
}