canina/frontend/application/components/Hero.tsx

200 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { motion, useMotionValue, useTransform, animate } from "motion/react";
import { ChevronLeft } 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>
);
}
function Typewriter({ text }: { text: string }) {
const [displayText, setDisplayText] = useState("");
useEffect(() => {
let i = 0;
const interval = setInterval(() => {
setDisplayText(text.slice(0, i));
i++;
if (i > text.length) clearInterval(interval);
}, 150);
return () => clearInterval(interval);
}, [text]);
return (
<div className="text-4xl lg:text-6xl font-black text-canina-blue font-vazir flex flex-row-reverse items-center">
<span className="relative">
{toPersian(displayText)}
<motion.span
animate={{ opacity: [0, 1, 0] }}
transition={{ duration: 0.8, repeat: Infinity }}
className="absolute -left-1 top-0 h-full w-[3px] bg-canina-blue"
/>
</span>
</div>
);
}
import { useRouter } from 'next/navigation';
export default function Hero() {
const router = useRouter();
const getText = useSettingsStore(state => state.getText);
const title = getText('hero_title', "تخصص آلمانی در خدمت\nسلامت پت‌های خانگی");
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">
{/* 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">{getText('hero_badge', "تخصص دارویی از آلمان")}</span>
</div>
<h1 className="text-4xl lg:text-7xl font-black text-medical-gray-900 leading-[1.1] mb-6">
{titleParts[0]} <br />
{titleParts[1] && <span className="text-canina-blue font-vazir">{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: getText(
'hero_desc',
'بیش از <span className="font-bold text-canina-blue">۴۰ سال</span> تجربه نوآورانه در تولید مکمل‌های درمانی با بالاترین استاندارد کیفی «گرید دارویی اختصاصی». راهکار هوشمند برای هر نیاز بالینی.'
)
}}
/>
<div className="flex flex-wrap justify-center lg:justify-start gap-4">
<button
onClick={() => {
const element = document.getElementById('canina-advisor');
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
}}
className="bg-medical-gray-900 text-white px-10 py-5 rounded-full font-bold text-lg hover:bg-canina-blue hover:shadow-2xl transition-all flex items-center gap-2 group font-vazir"
>
{getText('hero_btn_advisor', "دستیار سلامت پت")}
<ChevronLeft className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
</button>
<button
onClick={() => router.push('/shop')}
className="bg-white border-2 border-medical-gray-200 text-medical-gray-700 px-10 py-5 rounded-full font-bold text-lg hover:border-canina-blue hover:text-canina-blue transition-all font-vazir"
>
{getText('hero_btn_products', "مشاهده محصولات")}
</button>
</div>
</motion.div>
{/* Stats */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.8, duration: 0.6 }}
className="grid grid-cols-3 gap-8 mt-16 pt-8 border-t border-medical-gray-100"
>
<div className="flex flex-col items-center lg:items-end">
<Typewriter text={getText('hero_stat_founded', "۱۹۸۴ سال تأسیس")} />
</div>
<div className="flex flex-col items-center lg:items-end">
<StatCounter target={40} />
<div className="text-xs text-medical-gray-500 font-bold uppercase tracking-tight mt-3 font-vazir">{getText('hero_stat_agencies', "نمایندگی فعال")}</div>
</div>
<div className="flex flex-col items-center lg:items-end">
<div className="relative overflow-hidden group">
<motion.div
className="text-4xl lg:text-6xl font-black text-canina-blue font-vazir relative z-10"
>
۱۰۰٪
</motion.div>
<motion.div
initial={{ x: "-100%" }}
animate={{ x: "200%" }}
transition={{ duration: 3, repeat: Infinity, ease: "linear" }}
className="absolute inset-0 bg-gradient-to-r from-transparent via-white/40 to-transparent skew-x-12 z-20 pointer-events-none"
/>
</div>
<div className="text-xs text-medical-gray-500 font-bold uppercase tracking-tight mt-3 font-vazir">{getText('hero_stat_german_formula', "فرمول آلمانی")}</div>
</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-medical-gray-100 rounded-[2rem] overflow-hidden border-4 border-white shadow-2xl relative">
<img
src="https://images.unsplash.com/photo-1583337130417-3346a1be7dee?auto=format&fit=crop&q=80&w=800"
alt="German Veterinary Expert"
className="w-full h-full object-cover grayscale-[20%] hover:grayscale-0 transition-all duration-700"
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]">{getText('hero_image_badge', "سرآمد علمی در پزشکی پت‌ها")}</div>
<div className="text-xl font-bold italic tracking-tighter">{getText('hero_image_title', "مکمل‌های تایید شده دامپزشکی")}</div>
</div>
</div>
</motion.div>
{/* Badge */}
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
className="absolute -top-6 -right-6 lg:-top-10 lg:-right-10 z-20 w-32 h-32 lg:w-40 lg:h-40 bg-white shadow-xl rounded-full p-1 border-2 border-dashed border-canina-blue flex items-center justify-center text-center p-4"
>
<div className="flex flex-col items-center">
<span className="text-2xl lg:text-3xl font-black text-canina-blue leading-none tracking-tighter">DE</span>
<span className="text-[8px] lg:text-[10px] font-bold text-medical-gray-500 uppercase tracking-widest mt-1">{getText('hero_quality_standard', "استاندارد کیفی آلمان")}</span>
</div>
</motion.div>
</div>
</div>
</section>
);
}