209 lines
9.9 KiB
TypeScript
209 lines
9.9 KiB
TypeScript
"use client";
|
|
|
|
import React, { useEffect, useRef } from "react";
|
|
import Link from "next/link";
|
|
import Image from "next/image";
|
|
|
|
interface FeatureItem {
|
|
title: string;
|
|
desc: string;
|
|
icon: string;
|
|
image: string;
|
|
imageAlt: string;
|
|
defaultActive?: boolean;
|
|
delay: number;
|
|
}
|
|
|
|
/* SVG icons matching the original icon font shapes */
|
|
const IdeaIcon = () => (
|
|
<svg width="36" height="36" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M32 6C21.5 6 13 14.5 13 25c0 7.4 4 13.8 10 17.2V48h18v-5.8C47 38.8 51 32.4 51 25c0-10.5-8.5-19-19-19z" stroke="white" strokeWidth="3" strokeLinejoin="round" fill="none" />
|
|
<path d="M23 48h18M25 54h14M29 60h6" stroke="white" strokeWidth="3" strokeLinecap="round" />
|
|
<path d="M32 14v4M22 18l2.8 2.8M42 18l-2.8 2.8" stroke="white" strokeWidth="2.5" strokeLinecap="round" />
|
|
</svg>
|
|
);
|
|
|
|
const GrowthIcon = () => (
|
|
<svg width="36" height="36" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M8 48L22 30l10 8L46 16l10 10" stroke="white" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
<path d="M46 8h10v10" stroke="white" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
<rect x="8" y="50" width="8" height="8" rx="1" fill="white" />
|
|
<rect x="20" y="42" width="8" height="16" rx="1" fill="white" />
|
|
<rect x="32" y="36" width="8" height="22" rx="1" fill="white" />
|
|
<rect x="44" y="28" width="8" height="30" rx="1" fill="white" />
|
|
</svg>
|
|
);
|
|
|
|
const TeamIcon = () => (
|
|
<svg width="36" height="36" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<circle cx="32" cy="18" r="9" stroke="white" strokeWidth="3" fill="none" />
|
|
<path d="M14 52c0-9.9 8.1-18 18-18s18 8.1 18 18" stroke="white" strokeWidth="3" strokeLinecap="round" fill="none" />
|
|
<circle cx="14" cy="22" r="6" stroke="white" strokeWidth="2.5" fill="none" />
|
|
<path d="M2 50c0-7.2 5.4-13 12-13" stroke="white" strokeWidth="2.5" strokeLinecap="round" fill="none" />
|
|
<circle cx="50" cy="22" r="6" stroke="white" strokeWidth="2.5" fill="none" />
|
|
<path d="M62 50c0-7.2-5.4-13-12-13" stroke="white" strokeWidth="2.5" strokeLinecap="round" fill="none" />
|
|
</svg>
|
|
);
|
|
|
|
const ArrowIcon = () => (
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M5 12h14M13 6l6 6-6 6" stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
</svg>
|
|
);
|
|
|
|
const features: FeatureItem[] = [
|
|
{
|
|
title: "Comprehensive digital development",
|
|
desc: "Expert web, app development and e-commerce solutions.",
|
|
icon: "/assets/images/services/feature/comprehensive.png",
|
|
image: "/assets/images/services/feature/1-1.webp",
|
|
imageAlt: "Comprehensive Digital Development",
|
|
delay: 0,
|
|
},
|
|
{
|
|
title: "Strategic online growth solutions",
|
|
desc: "Strategic SEO and digital marketing for growth.",
|
|
icon: "/assets/images/services/feature/strategic.png",
|
|
image: "/assets/images/services/feature/1-2.webp",
|
|
imageAlt: "Strategic Online Growth Solutions",
|
|
defaultActive: true,
|
|
delay: 200,
|
|
},
|
|
{
|
|
title: "Creative design and branding excellence",
|
|
desc: "Creative graphic design and branding strategy services.",
|
|
icon: "/assets/images/services/feature/creative.png",
|
|
image: "/assets/images/services/feature/1-3.webp",
|
|
imageAlt: "Creative Design and Branding Excellence",
|
|
delay: 400,
|
|
},
|
|
];
|
|
|
|
const FeaturesSection = () => {
|
|
const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
|
|
|
|
useEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
const el = entry.target as HTMLElement;
|
|
const delay = parseInt(el.dataset.wowDelay || "0");
|
|
setTimeout(() => {
|
|
el.style.opacity = "1";
|
|
el.style.transform = "translateY(0)";
|
|
el.style.visibility = "visible";
|
|
}, delay);
|
|
observer.unobserve(el);
|
|
}
|
|
});
|
|
},
|
|
{ threshold: 0.1 }
|
|
);
|
|
|
|
itemRefs.current.forEach((el) => {
|
|
if (el) observer.observe(el);
|
|
});
|
|
|
|
return () => observer.disconnect();
|
|
}, []);
|
|
|
|
return (
|
|
<section className="fo-section">
|
|
<div className="fo-shapes">
|
|
<div className="fo-shape-one"></div>
|
|
<div className="fo-shape-two"></div>
|
|
</div>
|
|
<div className="fo-container">
|
|
<div className="history-two__title text-center">
|
|
<div className="sec-title">
|
|
<div className="sec-title__shape"></div>
|
|
<h6 className="sec-title__tagline">Strategic Digital Services</h6>
|
|
<h3 className="sec-title__title">Innovation & Growth</h3>
|
|
</div>
|
|
</div>
|
|
<div className="fo-row">
|
|
{features.map((feature, index) => (
|
|
<div className="fo-col" key={index}>
|
|
<div
|
|
ref={(el) => { itemRefs.current[index] = el; }}
|
|
className={`fo-item${feature.defaultActive ? " fo-item--active" : ""}`}
|
|
data-wow-delay={String(feature.delay)}
|
|
style={{
|
|
opacity: 0,
|
|
transform: "translateY(40px)",
|
|
transition: `opacity 1.5s ease ${feature.delay}ms, transform 1.5s ease ${feature.delay}ms`,
|
|
visibility: "hidden",
|
|
}}
|
|
>
|
|
{/* Hover overlay card — slides down from top */}
|
|
<div className="fo-hover-card">
|
|
{/* Circle icon badge above the hover card */}
|
|
<div className="fo-hover-icon">
|
|
<Image
|
|
src={feature.icon}
|
|
alt={feature.title}
|
|
width={50}
|
|
height={50}
|
|
style={{ objectFit: "contain" }}
|
|
/>
|
|
</div>
|
|
<h3 className="fo-hover-title">{feature.title}</h3>
|
|
{/* <Link href="#" className="fo-hover-btn">
|
|
<ArrowIcon />
|
|
</Link> */}
|
|
</div>
|
|
|
|
{/* Main card */}
|
|
<div className="fo-card">
|
|
{/* Top dark section */}
|
|
<div className="fo-card-top">
|
|
{/* Mobile only icon */}
|
|
<div className="fo-mobile-icon d-md-none mb-3">
|
|
<Image
|
|
src={feature.icon}
|
|
alt={feature.desc}
|
|
width={40}
|
|
height={40}
|
|
style={{ objectFit: "contain" }}
|
|
/>
|
|
</div>
|
|
<h3 className="fo-card-title">{feature.title}</h3>
|
|
{/* <Link href="#" className="fo-card-btn d-none d-md-flex">
|
|
<ArrowIcon />
|
|
</Link> */}
|
|
<p className="fo-card-desc">{feature.desc}</p>
|
|
</div>
|
|
{/* Bottom white section with image + floating icon */}
|
|
<div className="fo-card-bottom d-none d-md-block">
|
|
<div className="fo-card-image">
|
|
<Image
|
|
src={feature.image}
|
|
alt={feature.imageAlt}
|
|
width={340}
|
|
height={123}
|
|
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
|
/>
|
|
</div>
|
|
<div className="fo-card-icon">
|
|
<Image
|
|
src={feature.icon}
|
|
alt={feature.desc}
|
|
width={50}
|
|
height={50}
|
|
style={{ objectFit: "contain" }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default FeaturesSection;
|