169 lines
7.3 KiB
TypeScript
169 lines
7.3 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useEffect, useCallback } from "react";
|
||
import ContactPopup from '@/components/common/ContactPopup/ContactPopup';
|
||
|
||
const features = [
|
||
{
|
||
img: "/assets/img/home/section5/conversion.webp",
|
||
title: "Conversion-Focused Website Architecture",
|
||
desc: "We design every page with one goal — turning visitors into leads or customers. From clear CTAs to strategic layout flow, your website will guide users toward action.",
|
||
},
|
||
{
|
||
img: "/assets/img/home/section5/speed.webp",
|
||
title: "Speed & Performance Optimized",
|
||
desc: "A slow website kills conversions. We build lightweight, optimized websites that load fast, improve user experience, and boost your Google rankings.",
|
||
},
|
||
{
|
||
img: "/assets/img/home/section5/seo.webp",
|
||
title: "SEO-Ready Development",
|
||
desc: "Your website is built with clean code, proper structure, meta setup, schema basics, and search-friendly URLs — helping you rank better on Google from day one.",
|
||
},
|
||
{
|
||
img: "/assets/img/home/section5/mobile.webp",
|
||
title: "Mobile-First & Fully Responsive",
|
||
desc: "Over 70% of traffic comes from mobile. We ensure your website looks perfect and functions smoothly on smartphones, tablets, and desktops.",
|
||
}
|
||
];
|
||
|
||
// Group features into pairs (columns of 2 cards each)
|
||
const columns: typeof features[] = [];
|
||
for (let i = 0; i < features.length; i += 2) {
|
||
columns.push(features.slice(i, i + 2));
|
||
}
|
||
|
||
const KeyFeatures = () => {
|
||
const [currentIndex, setCurrentIndex] = useState(0);
|
||
const [visibleCols, setVisibleCols] = useState(2);
|
||
const [isContactOpen, setIsContactOpen] = useState(false);
|
||
|
||
const totalCols = columns.length; // 2 columns
|
||
|
||
useEffect(() => {
|
||
const handleResize = () => {
|
||
if (window.innerWidth <= 576) setVisibleCols(1);
|
||
else setVisibleCols(2);
|
||
};
|
||
handleResize();
|
||
window.addEventListener("resize", handleResize);
|
||
return () => window.removeEventListener("resize", handleResize);
|
||
}, []);
|
||
|
||
const maxIndex = Math.max(0, totalCols - visibleCols);
|
||
|
||
const handleNext = useCallback(() => {
|
||
setCurrentIndex((prev) => (prev < maxIndex ? prev + 1 : 0));
|
||
}, [maxIndex]);
|
||
|
||
const handlePrev = useCallback(() => {
|
||
setCurrentIndex((prev) => (prev > 0 ? prev - 1 : maxIndex));
|
||
}, [maxIndex]);
|
||
|
||
// Auto-slide every 5s
|
||
useEffect(() => {
|
||
const timer = setInterval(handleNext, 5000);
|
||
return () => clearInterval(timer);
|
||
}, [handleNext]);
|
||
|
||
// Clamp index on resize
|
||
useEffect(() => {
|
||
if (currentIndex > maxIndex) setCurrentIndex(maxIndex);
|
||
}, [maxIndex, currentIndex]);
|
||
|
||
return (
|
||
<section className="kf-section kf-section-light">
|
||
<div className="kf-container">
|
||
|
||
{/* Left – Single Full Image */}
|
||
<div className="kf-image-column">
|
||
<img
|
||
src="/assets/img/home/section4/4.webp"
|
||
alt="Key Features"
|
||
style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', borderRadius: '12px' }}
|
||
loading="lazy"
|
||
/>
|
||
</div>
|
||
|
||
{/* Right – Slider */}
|
||
<div className="kf-slider-column">
|
||
<div className="kf-header">
|
||
<h2 className="kf-title">
|
||
Key <span className="kf-highlight">Features</span>
|
||
</h2>
|
||
</div>
|
||
|
||
<div className="kf-slider-window">
|
||
<div
|
||
className="kf-slider-track"
|
||
style={{
|
||
transform: `translateX(calc(-${currentIndex} * (100% + 1.5rem) / ${visibleCols}))`,
|
||
}}
|
||
>
|
||
{columns.map((column, colIdx) => (
|
||
<div
|
||
key={colIdx}
|
||
className="kf-column-wrapper"
|
||
style={{
|
||
flexBasis: `calc((100% - (${visibleCols} - 1) * 1.5rem) / ${visibleCols})`,
|
||
width: `calc((100% - (${visibleCols} - 1) * 1.5rem) / ${visibleCols})`,
|
||
}}
|
||
>
|
||
{column.map((feature, idx) => (
|
||
<div key={idx} className="kf-card">
|
||
<div className="kf-icon-box">
|
||
<img
|
||
src={feature.img}
|
||
alt={feature.title}
|
||
className="kf-card-img"
|
||
loading="lazy"
|
||
/>
|
||
</div>
|
||
<div className="kf-card-content">
|
||
<h5 className="kf-card-name">{feature.title}</h5>
|
||
<p className="kf-card-desc">
|
||
{feature.desc}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
{column.length < 2 && <div className="kf-card-placeholder" />}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Dots */}
|
||
<div className="kf-dots">
|
||
{Array.from({ length: maxIndex + 1 }).map((_, idx) => (
|
||
<div
|
||
key={idx}
|
||
className={`kf-dot${currentIndex === idx ? " kf-dot-active" : ""}`}
|
||
onClick={() => setCurrentIndex(idx)}
|
||
/>
|
||
))}
|
||
</div>
|
||
|
||
{/* Controls + CTA */}
|
||
<div className="kf-controls-row">
|
||
<div className="kf-controls">
|
||
<button className="kf-control-btn" onClick={handlePrev} aria-label="Previous">
|
||
←
|
||
</button>
|
||
<button className="kf-control-btn" onClick={handleNext} aria-label="Next">
|
||
→
|
||
</button>
|
||
</div>
|
||
<button onClick={() => setIsContactOpen(true)} className="kf-demo-btn">
|
||
Book Free Strategy Call
|
||
<i className="fa-solid fa-angle-right"></i></button>
|
||
</div>
|
||
</div>
|
||
|
||
<ContactPopup isOpen={isContactOpen} onClose={() => setIsContactOpen(false)} />
|
||
</div >
|
||
</section >
|
||
);
|
||
};
|
||
|
||
export default KeyFeatures;
|