224 lines
13 KiB
TypeScript
224 lines
13 KiB
TypeScript
/* eslint-disable @next/next/no-img-element */
|
||
"use client";
|
||
import { motion, animate } from "motion/react";
|
||
import { ChevronLeft, Globe, ShieldCheck, Calendar } from "lucide-react";
|
||
import { useEffect, useState } from "react";
|
||
import { toPersian } from "../lib/utils";
|
||
import { useSettingsStore } from "../lib/store/settingsStore";
|
||
|
||
function StatCounter({ target }: { target: number }) {
|
||
const [displayValue, setDisplayValue] = useState(0);
|
||
|
||
useEffect(() => {
|
||
const controls = animate(0, target, {
|
||
duration: 3,
|
||
ease: [0.16, 1, 0.3, 1], // Custom cubic-bezier for a more polished feel
|
||
onUpdate: (latest) => setDisplayValue(Math.round(latest))
|
||
});
|
||
return controls.stop;
|
||
}, [target]);
|
||
|
||
return (
|
||
<motion.div
|
||
initial={{ scale: 0.8, opacity: 0 }}
|
||
animate={{ scale: 1, opacity: 1 }}
|
||
transition={{ duration: 2.5, ease: "easeOut" }}
|
||
className="text-4xl lg:text-6xl font-black text-canina-blue font-vazir origin-right flex items-center"
|
||
>
|
||
<motion.span
|
||
animate={{ scale: [1, 1.1, 1] }}
|
||
transition={{ duration: 3, ease: "easeInOut" }}
|
||
>
|
||
{toPersian(displayValue)}+
|
||
</motion.span>
|
||
</motion.div>
|
||
);
|
||
}
|
||
|
||
import { useRouter } from 'next/navigation';
|
||
import { Banner } from "../lib/types";
|
||
|
||
export default function Hero({ banners = [], onShopNavigate }: { banners?: Banner[]; onShopNavigate?: () => void }) {
|
||
const router = useRouter();
|
||
const getText = useSettingsStore((state) => state?.getText || ((_k: string, fb: string) => fb));
|
||
const isInitialized = useSettingsStore((state) => state?.isInitialized ?? false);
|
||
const [mounted, setMounted] = useState(false);
|
||
|
||
useEffect(() => {
|
||
setMounted(true);
|
||
}, []);
|
||
|
||
const defaultTitle = banners.length > 0 && banners[0].title ? banners[0].title : "تخصص آلمانی در خدمت\nسلامت پتهای خانگی";
|
||
const defaultSubtitle = banners.length > 0 && banners[0].subtitle ? banners[0].subtitle : 'از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهرهگیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکملهای دامپزشکی را تعریف میکند. کنینا نماینده رسمی این برند در ایران است.';
|
||
|
||
const title = (mounted && isInitialized ? getText('hero_title', '') : '') || defaultTitle;
|
||
const subtitle = (mounted && isInitialized ? getText('hero_desc', '') : '') || defaultSubtitle;
|
||
const titleParts = title.split('\n');
|
||
|
||
return (
|
||
<section className="relative overflow-hidden bg-white py-20 lg:py-32 border-b border-medical-gray-100">
|
||
{/* Background patterns */}
|
||
<div className="absolute top-0 left-0 w-full h-full opacity-[0.03] pointer-events-none select-none overflow-hidden">
|
||
<div className="absolute top-0 right-0 w-[800px] h-[800px] bg-canina-blue rounded-full blur-[120px] -mr-96 -mt-96" />
|
||
<div className="absolute bottom-0 left-0 w-[600px] h-[600px] bg-medical-gray-500 rounded-full blur-[100px] -ml-40 -mb-40" />
|
||
</div>
|
||
|
||
<div className="max-w-7xl mx-auto px-4 relative flex flex-col lg:flex-row items-center gap-12 mb-16 lg:mb-20">
|
||
{/* Content */}
|
||
<div className="lg:w-1/2 text-center lg:text-right">
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.6 }}
|
||
>
|
||
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canina-blue/5 border border-canina-blue/10 rounded-full mb-6">
|
||
<span className="w-2 h-2 rounded-full bg-canina-blue animate-pulse" />
|
||
<span className="text-canina-blue text-xs font-bold uppercase tracking-widest leading-none">
|
||
{mounted && isInitialized ? getText('hero_badge', "از ۱۹۸۴ در خدمت سلامت حیوانات") : "از ۱۹۸۴ در خدمت سلامت حیوانات"}
|
||
</span>
|
||
</div>
|
||
|
||
<h1 className="text-4xl lg:text-7xl font-black text-medical-gray-900 leading-[1.2] mb-6 font-lalezar tracking-wide">
|
||
{titleParts[0]} <br />
|
||
{titleParts[1] && <span className="text-canina-blue">{titleParts[1]}</span>}
|
||
</h1>
|
||
|
||
<p
|
||
className="text-lg lg:text-xl text-medical-gray-600 mb-10 max-w-2xl mx-auto lg:mx-0 leading-relaxed font-vazir animate-fade-in"
|
||
dangerouslySetInnerHTML={{
|
||
__html: subtitle
|
||
}}
|
||
/>
|
||
|
||
<div className="flex flex-wrap justify-center lg:justify-start gap-4 sm:gap-6">
|
||
<button
|
||
onClick={() => {
|
||
const element = document.getElementById('canino-advisor');
|
||
if (element) {
|
||
element.scrollIntoView({ behavior: 'smooth' });
|
||
}
|
||
}}
|
||
className="bg-canina-blue text-white px-10 py-5 rounded-full font-bold text-lg hover:bg-canina-blue/90 hover:shadow-2xl focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all flex items-center gap-2 group font-vazir min-h-[58px] shadow-lg shadow-canina-blue/20 cursor-pointer"
|
||
>
|
||
{mounted && isInitialized ? getText('hero_btn_advisor', "دستیار سلامت پت") : "دستیار سلامت پت"}
|
||
<ChevronLeft className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
|
||
</button>
|
||
<button
|
||
onClick={() => {
|
||
if (onShopNavigate) {
|
||
onShopNavigate();
|
||
} else {
|
||
router.push('/shop');
|
||
}
|
||
}}
|
||
className="bg-white border-2 border-medical-gray-900 text-medical-gray-900 px-10 py-5 rounded-full font-bold text-lg hover:bg-medical-gray-50 focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all font-vazir min-h-[58px] shadow-sm cursor-pointer"
|
||
>
|
||
{mounted && isInitialized ? getText('hero_btn_products', "مشاهده محصولات") : "مشاهده محصولات"}
|
||
</button>
|
||
</div>
|
||
</motion.div>
|
||
</div>
|
||
|
||
{/* Visual Element */}
|
||
<div className="lg:w-1/2 relative">
|
||
<motion.div
|
||
initial={{ opacity: 0, scale: 0.9, rotate: -5 }}
|
||
animate={{ opacity: 1, scale: 1, rotate: 0 }}
|
||
transition={{ duration: 1, ease: "easeOut" }}
|
||
className="relative z-10"
|
||
>
|
||
<div className="aspect-square bg-gradient-to-br from-slate-200 to-slate-300 rounded-[2.5rem] overflow-hidden border-4 border-white shadow-2xl relative">
|
||
<img
|
||
src={(mounted && isInitialized ? getText('hero_image_url', '') : '') || (banners.length > 0 && banners[0].imageUrl ? banners[0].imageUrl : "/assets/images/hero-section-image.png")}
|
||
alt={banners.length > 0 ? banners[0].title : "Canina Pharma Germany"}
|
||
className="w-full h-full object-cover"
|
||
loading="eager"
|
||
referrerPolicy="no-referrer"
|
||
/>
|
||
<div className="absolute bottom-0 left-0 right-0 p-8 bg-gradient-to-t from-black/80 to-transparent text-white text-right">
|
||
<div className="text-sm font-medium mb-1 opacity-80 uppercase tracking-widest text-[10px]">
|
||
{mounted && isInitialized ? getText('hero_image_badge', "سرآمد علمی در پزشکی پتها") : "سرآمد علمی در پزشکی پتها"}
|
||
</div>
|
||
<div className="text-xl font-bold italic tracking-tighter">
|
||
{mounted && isInitialized ? getText('hero_image_title', "مکملهای تایید شده دامپزشکی با گواهی IFS") : "مکملهای تایید شده دامپزشکی با گواهی IFS"}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Quality Badge inside the image container to prevent text collision */}
|
||
<motion.div
|
||
animate={{ rotate: 360 }}
|
||
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
|
||
className="absolute top-6 right-6 lg:top-8 lg:right-8 z-20 w-24 h-24 lg:w-28 lg:h-28 bg-white shadow-2xl rounded-full p-2 border-2 border-dashed border-canina-blue flex items-center justify-center text-center"
|
||
>
|
||
<div className="flex flex-col items-center">
|
||
<span className="text-xl lg:text-2xl font-black text-canina-blue leading-none tracking-tighter">DE</span>
|
||
<span className="text-[7px] lg:text-[8px] font-bold text-medical-gray-500 uppercase tracking-widest mt-0.5 leading-tight">
|
||
{mounted && isInitialized ? getText('hero_quality_standard', "استاندارد کیفی آلمان (IFS & HACCP)") : "استاندارد کیفی آلمان (IFS & HACCP)"}
|
||
</span>
|
||
</div>
|
||
</motion.div>
|
||
|
||
{/* 3D Action Badge clarifying the 3D mark */}
|
||
<div className="absolute bottom-28 right-6 bg-canina-gold text-medical-gray-900 px-4 py-2 rounded-2xl text-xs font-black shadow-2xl z-20 flex items-center gap-1.5 font-vazir border border-white/20 select-none animate-bounce">
|
||
<span className="text-sm">✨</span>
|
||
<span>فرمول ۳کاره (تاثیر سهبعدی)</span>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Stats - 3 side-by-side cards with centered text on all screens */}
|
||
<div className="max-w-7xl mx-auto px-2 sm:px-4 relative">
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ delay: 0.8, duration: 0.6 }}
|
||
className="grid grid-cols-3 gap-2 sm:gap-6 py-6 sm:py-10 border-t border-medical-gray-150"
|
||
>
|
||
{/* Stat 1: Founded Year */}
|
||
<div className="bg-medical-gray-50/50 border border-medical-gray-100 rounded-2xl sm:rounded-3xl p-2.5 sm:p-6 flex flex-col sm:flex-row items-center justify-center text-center sm:text-right gap-2 sm:gap-6 group hover:shadow-xl hover:shadow-canina-blue/5 transition-all">
|
||
<div className="w-9 h-9 sm:w-14 sm:h-14 bg-white rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue shadow-sm group-hover:bg-canina-blue group-hover:text-white transition-all duration-300 flex-shrink-0">
|
||
<Calendar className="w-4 h-4 sm:w-7 sm:h-7" />
|
||
</div>
|
||
<div className="flex flex-col items-center sm:items-start text-center sm:text-right">
|
||
<div className="text-base sm:text-3xl font-black text-canina-blue font-vazir leading-none">۱۹۸۴</div>
|
||
<div className="text-[9px] sm:text-xs text-medical-gray-500 font-extrabold uppercase tracking-tight mt-1 sm:mt-2 font-vazir">
|
||
{mounted && isInitialized ? getText('hero_stat_founded', "سال تاسیس برند") : "سال تاسیس برند"}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Stat 2: Active Agencies */}
|
||
<div className="bg-medical-gray-50/50 border border-medical-gray-100 rounded-2xl sm:rounded-3xl p-2.5 sm:p-6 flex flex-col sm:flex-row items-center justify-center text-center sm:text-right gap-2 sm:gap-6 group hover:shadow-xl hover:shadow-canina-blue/5 transition-all">
|
||
<div className="w-9 h-9 sm:w-14 sm:h-14 bg-white rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue shadow-sm group-hover:bg-canina-blue group-hover:text-white transition-all duration-300 flex-shrink-0">
|
||
<Globe className="w-4 h-4 sm:w-7 sm:h-7" />
|
||
</div>
|
||
<div className="flex flex-col items-center sm:items-start text-center sm:text-right">
|
||
<div className="flex items-baseline justify-center sm:justify-start">
|
||
<StatCounter target={40} />
|
||
</div>
|
||
<div className="text-[9px] sm:text-xs text-medical-gray-500 font-extrabold uppercase tracking-tight mt-1 sm:mt-2 font-vazir">
|
||
{mounted && isInitialized ? getText('hero_stat_agencies', "نمایندگی فعال") : "نمایندگی فعال"}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Stat 3: German Formula */}
|
||
<div className="bg-medical-gray-50/50 border border-medical-gray-100 rounded-2xl sm:rounded-3xl p-2.5 sm:p-6 flex flex-col sm:flex-row items-center justify-center text-center sm:text-right gap-2 sm:gap-6 group hover:shadow-xl hover:shadow-canina-blue/5 transition-all">
|
||
<div className="w-9 h-9 sm:w-14 sm:h-14 bg-white rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue shadow-sm group-hover:bg-canina-blue group-hover:text-white transition-all duration-300 flex-shrink-0">
|
||
<ShieldCheck className="w-4 h-4 sm:w-7 sm:h-7" />
|
||
</div>
|
||
<div className="flex flex-col items-center sm:items-start text-center sm:text-right">
|
||
<div className="text-base sm:text-3xl font-black text-canina-blue font-vazir leading-none">۱۰۰٪</div>
|
||
<div className="text-[9px] sm:text-xs text-medical-gray-500 font-extrabold uppercase tracking-tight mt-1 sm:mt-2 font-vazir">
|
||
{mounted && isInitialized ? getText('hero_stat_german_formula', "فرمول آلمانی") : "فرمول آلمانی"}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|