fix hero btn and navigate on click bar

This commit is contained in:
priyanshuvish
2025-09-25 17:31:35 +05:30
parent 38a7b6a260
commit 9163e046d0
2 changed files with 137 additions and 271 deletions

View File

@@ -2,7 +2,8 @@ import React, { useState, useEffect, useCallback } from 'react';
import { ChevronLeft, ChevronRight } from 'lucide-react'; import { ChevronLeft, ChevronRight } from 'lucide-react';
import { navigateTo } from './Router'; import { navigateTo } from './Router';
import svgPaths from "../imports/svg-i1joeov37f"; import svgPaths from "../imports/svg-i1joeov37f";
import PrimaryCTAButton from './PrimaryCTAButton';
interface SlideData { interface SlideData {
id: number; id: number;
title: string; title: string;
@@ -11,12 +12,12 @@ interface SlideData {
ctaText: string; ctaText: string;
route: string; route: string;
} }
export default function HeroSection() { export default function HeroSection() {
const [currentSlide, setCurrentSlide] = useState(0); const [currentSlide, setCurrentSlide] = useState(0);
const [isAutoPlaying, setIsAutoPlaying] = useState(true); const [isAutoPlaying, setIsAutoPlaying] = useState(true);
const [progressValues, setProgressValues] = useState([0, 0, 0, 0, 0, 0]); const [progressValues, setProgressValues] = useState([0, 0, 0, 0, 0, 0]);
const slides: SlideData[] = [ const slides: SlideData[] = [
{ {
id: 1, id: 1,
@@ -32,7 +33,7 @@ export default function HeroSection() {
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", 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", shortTitle: "Leadership Development",
ctaText: "Explore Leadership Journeys", ctaText: "Explore Leadership Journeys",
route: '/services/leadership-development' route: '/services/leadership-development'
}, },
{ {
id: 3, id: 3,
@@ -67,25 +68,25 @@ export default function HeroSection() {
route: '/services/learning-facility' route: '/services/learning-facility'
} }
]; ];
const totalSlides = slides.length; const totalSlides = slides.length;
const slideDuration = 5000; // 5 seconds per slide const slideDuration = 5000; // 5 seconds per slide
// Auto-advance slides // Auto-advance slides
useEffect(() => { useEffect(() => {
if (!isAutoPlaying) return; if (!isAutoPlaying) return;
const interval = setInterval(() => { const interval = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % totalSlides); setCurrentSlide((prev) => (prev + 1) % totalSlides);
}, slideDuration); }, slideDuration);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [isAutoPlaying, totalSlides]); }, [isAutoPlaying, totalSlides]);
// Progress bar animation // Progress bar animation
useEffect(() => { useEffect(() => {
if (!isAutoPlaying) return; if (!isAutoPlaying) return;
const interval = setInterval(() => { const interval = setInterval(() => {
setProgressValues(prev => { setProgressValues(prev => {
const newProgress = [...prev]; const newProgress = [...prev];
@@ -103,10 +104,10 @@ export default function HeroSection() {
return newProgress; return newProgress;
}); });
}, 100); }, 100);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [currentSlide, isAutoPlaying]); }, [currentSlide, isAutoPlaying]);
// Reset progress when manually changing slides // Reset progress when manually changing slides
useEffect(() => { useEffect(() => {
setProgressValues(prev => { setProgressValues(prev => {
@@ -115,7 +116,7 @@ export default function HeroSection() {
return newProgress; return newProgress;
}); });
}, [currentSlide]); }, [currentSlide]);
const goToSlide = useCallback((slideIndex: number) => { const goToSlide = useCallback((slideIndex: number) => {
if (slideIndex !== currentSlide) { if (slideIndex !== currentSlide) {
setCurrentSlide(slideIndex); setCurrentSlide(slideIndex);
@@ -124,23 +125,23 @@ export default function HeroSection() {
setTimeout(() => setIsAutoPlaying(true), 3000); setTimeout(() => setIsAutoPlaying(true), 3000);
} }
}, [currentSlide]); }, [currentSlide]);
const nextSlide = useCallback(() => { const nextSlide = useCallback(() => {
const next = (currentSlide + 1) % totalSlides; const next = (currentSlide + 1) % totalSlides;
goToSlide(next); goToSlide(next);
}, [currentSlide, totalSlides, goToSlide]); }, [currentSlide, totalSlides, goToSlide]);
const prevSlide = useCallback(() => { const prevSlide = useCallback(() => {
const prev = (currentSlide - 1 + totalSlides) % totalSlides; const prev = (currentSlide - 1 + totalSlides) % totalSlides;
goToSlide(prev); goToSlide(prev);
}, [currentSlide, totalSlides, goToSlide]); }, [currentSlide, totalSlides, goToSlide]);
// Pause auto-play on hover // Pause auto-play on hover
const handleMouseEnter = () => setIsAutoPlaying(false); const handleMouseEnter = () => setIsAutoPlaying(false);
const handleMouseLeave = () => setIsAutoPlaying(true); const handleMouseLeave = () => setIsAutoPlaying(true);
return ( return (
<section <section
className="hero-section" className="hero-section"
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
@@ -157,7 +158,7 @@ export default function HeroSection() {
<div className="hero-overlay" /> <div className="hero-overlay" />
</div> </div>
))} ))}
{/* Hero Content */} {/* Hero Content */}
<div className="hero-content"> <div className="hero-content">
<div className="hero-text-section"> <div className="hero-text-section">
@@ -167,144 +168,54 @@ export default function HeroSection() {
</h1> </h1>
{/* Dynamic CTA Button - Enhanced with Proper Navigation */} {/* 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(slides[currentSlide].route);
}}
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 */} <PrimaryCTAButton
<div className="text-layer relative shrink-0 overflow-hidden flex items-center" style={{ text={slides[currentSlide].ctaText}
height: '28px', onClick={() => navigateTo(slides[currentSlide].route)}
fontFamily: 'Inter, sans-serif', ariaLabel="Learn more about KLC"
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>
</div> </div>
{/* Bottom Navigation */} {/* Bottom Navigation */}
<div className="hero-navigation"> <div className="hero-navigation">
{/* Progress Section */} {/* Progress Section */}
<div className="hero-progress-container"> <div className="hero-progress-container">
{slides.map((slide, index) => ( {slides.map((slide, index) => (
<div <div
key={slide.id} key={slide.id}
className="hero-progress-item" className="hero-progress-item"
onClick={() => goToSlide(index)} onClick={() => goToSlide(index)}
> >
{/* Progress Bar */} {/* Progress Bar */}
<div <div
className={`hero-progress-segment ${index === currentSlide ? 'active' : ''}`} key={slide.id}
className="hero-progress-item"
onClick={() => navigateTo(slide.route)}
> >
<div {/* Progress Bar */}
className="hero-progress-fill" <div className={`hero-progress-segment ${index === currentSlide ? 'active' : ''}`}>
style={{ width: index === currentSlide ? `${progressValues[index]}%` : '0%' }} <div
/> className="hero-progress-fill"
</div> style={{ width: index === currentSlide ? `${progressValues[index]}%` : '0%' }}
/>
</div>
{/* Progress Number */} {/* Progress Number */}
<div className={`hero-progress-number ${index === currentSlide ? 'active' : ''}`}> <div className={`hero-progress-number ${index === currentSlide ? 'active' : ''}`}>
{String(index + 1).padStart(2, '0')} {String(index + 1).padStart(2, '0')}
</div> </div>
{/* Progress Text */} {/* Progress Text */}
<div className={`hero-progress-text ${index === currentSlide ? 'active' : ''}`}> <div className={`hero-progress-text ${index === currentSlide ? 'active' : ''}`}>
{slide.shortTitle} {slide.shortTitle}
</div>
</div> </div>
</div> </div>
))} ))}
</div> </div>
{/* Navigation Arrows */} {/* Navigation Arrows */}
<div className="hero-controls"> <div className="hero-controls">
<button <button

View File

@@ -1,146 +1,101 @@
import React, { useEffect } from 'react'; import React, { useState } from 'react';
import svgPaths from "../imports/svg-i1joeov37f"; import { ArrowRight } from 'lucide-react';
import { navigateTo } from './Router';
interface PrimaryCTAButtonProps { interface PrimaryCTAButtonProps {
text: string; text: string;
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void; onClick: () => void;
className?: string;
ariaLabel?: string; ariaLabel?: string;
debugId?: string; // Add debug identifier className?: string;
disabled?: boolean;
} }
export const PrimaryCTAButton: React.FC<PrimaryCTAButtonProps> = ({ export function PrimaryCTAButton({
text, text,
onClick, onClick,
ariaLabel,
className = '', className = '',
ariaLabel, disabled = false
debugId = 'unknown' }: PrimaryCTAButtonProps) {
}) => { const [isHovered, setIsHovered] = useState(false);
// Debug: Log when component mounts
useEffect(() => {
console.log(`PrimaryCTAButton ${debugId} mounted`);
}, [debugId]);
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
console.log(`Primary CTA Button ${debugId} clicked with text: "${text}"`); // Debug log
// Handle webinars navigation
if (text === "Join Our Webinars" || text === "Explore Webinars" || text === "View Webinars") {
console.log(`Navigating to webinars page for ${debugId}`);
navigateTo('/webinars');
} else if (text === "Register Free" || text === "Watch Replay" || text === "Launch in Zoom") {
// These are handled by individual webinar detail pages
console.log(`Webinar CTA handled by detail page for ${debugId}`);
} else if (onClick) {
console.log(`Custom onClick handler found for ${debugId}, executing it`); // Debug log
onClick(e);
} else {
console.log(`No custom onClick for ${debugId}, navigating to webcast page`); // Debug log
// Navigate to webcast page by default
navigateTo('/learning/webcast');
}
};
return ( return (
<button <button
className={`primary-cta-button group box-border content-stretch flex flex-row gap-2.5 items-center justify-start p-0 relative cursor-pointer overflow-hidden ${className}`} onClick={onClick}
style={{ disabled={disabled}
background: 'transparent', aria-label={ariaLabel || text}
border: 'none', className={`primary-cta-button ${className}`}
width: 'fit-content' // Perfect width - no extra horizontal space onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '12px',
padding: '8px 20px',
borderRadius: '10px',
border: 'none',
cursor: disabled ? 'not-allowed' : 'pointer',
fontSize: 'var(--font-body-lg)',
fontWeight: 'var(--font-weight-h3)',
fontFamily: 'var(--font-family-base)',
backgroundColor: disabled ? '#9CA3AF' : 'var(--color-primary)',
color: '#FFFFFF',
boxShadow: disabled
? 'none'
: '0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06)',
transition: 'all 300ms ease-in-out',
position: 'relative',
overflow: 'hidden',
opacity: disabled ? 0.6 : 1,
transform: isHovered && !disabled ? 'translateY(-2px)' : 'translateY(0)',
...(isHovered && !disabled && {
backgroundColor: '#030359', // Darker shade of primary brand color
boxShadow: '0 8px 25px rgba(4, 4, 91, 0.3), 0 4px 6px rgba(4, 4, 91, 0.1)'
})
}}
>
{/* Text */}
<span
style={{
fontSize: 'var(--font-body-lg)',
fontWeight: 'var(--font-weight-h3)',
fontFamily: 'var(--font-family-base)',
color: '#FFFFFF',
whiteSpace: 'nowrap'
}} }}
onClick={handleClick}
aria-label={ariaLabel || text}
> >
{/* Icon Container with Slide Animation */} {text}
<div className="relative shrink-0 size-[50px] overflow-hidden"> </span>
{/* Background Rectangle - Consistent Yellow Color */}
<div className="absolute inset-0 bg-[#F8C301]" /> {/* Arrow icon with enhanced animation */}
<span
{/* Icon Layer - Sliding Animation */} style={{
<div className="icon-layer absolute inset-0 w-full h-full"> display: 'flex',
{/* Primary Arrow - Slides out diagonally up-right */} alignItems: 'center',
<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"> justifyContent: 'center',
<svg width: '20px',
className="block w-full h-full" height: '20px',
fill="none" borderRadius: '50%',
preserveAspectRatio="none" backgroundColor: 'rgba(255, 255, 255, 0.2)',
viewBox="0 0 50 50" transition: 'all 300ms ease-in-out',
> transform: isHovered && !disabled ? 'translateX(4px) scale(1.1)' : 'translateX(0) scale(1)',
<g clipPath="url(#clip0_primary_cta_primary)"> ...(isHovered && !disabled && {
<path d={svgPaths.p5b8d700} fill="white" /> backgroundColor: 'rgba(255, 255, 255, 0.3)'
<path d={svgPaths.p30b71a00} fill="white" /> })
</g> }}
<defs> >
<clipPath id="clip0_primary_cta_primary"> <ArrowRight
<rect fill="white" height="50" width="50" /> size={14}
</clipPath> style={{
</defs> color: '#FFFFFF',
</svg> transition: 'all 300ms ease-in-out'
</div> }}
/>
{/* Secondary Arrow - Slides in from bottom-left */} </span>
<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"> </button>
<svg
className="block w-full h-full"
fill="none"
preserveAspectRatio="none"
viewBox="0 0 50 50"
>
<g clipPath="url(#clip0_primary_cta_secondary)">
<path d={svgPaths.p5b8d700} fill="white" />
<path d={svgPaths.p30b71a00} fill="white" />
</g>
<defs>
<clipPath id="clip0_primary_cta_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',
width: 'fit-content' // Perfect text width - no extra horizontal space
}}>
{/* 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',
fontFamily: 'Inter, sans-serif',
fontSize: '20px',
fontWeight: '400',
lineHeight: '28px'
}}
>
{text}
</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',
fontFamily: 'Inter, sans-serif',
fontSize: '20px',
fontWeight: '400',
lineHeight: '28px'
}}
>
{text}
</div>
</div>
</button>
); );
}; }
// Named exports for backward compatibility
export const PrimaryCTAButtonProps = PrimaryCTAButton;
export default PrimaryCTAButton;