fix(responsive): resolve header mobile overlap, stat box alignment, quality badge placement, and add back-to-top button

- Fix Header mobile logo/button overflow on 320px-375px screens by making logo text truncate gracefully & action buttons compact
- Make 3 hero stat boxes stay side-by-side in a 3-column grid with centered icons/text on mobile screens
- Adjust 'کیفیت / استانداردهای فوق‌دارویی' label position so it stays contained within the image boundaries without overflowing the screen
- Add interactive Back to Top button (both floating and footer button) for quick navigation
This commit is contained in:
parsa aghaei 2026-07-21 14:06:37 +03:30
parent 56515f24c6
commit 88b2fdbb14
4 changed files with 105 additions and 70 deletions

View File

@ -75,18 +75,18 @@ export default function HomeClient() {
{/* About Section Teaser */}
<section className="py-16 bg-white overflow-hidden font-sans">
<div className="max-w-7xl mx-auto px-4 grid lg:grid-cols-2 gap-16 lg:gap-24 items-center">
<div className="relative">
<div className="absolute -top-10 -right-10 w-40 h-40 bg-canina-blue/5 rounded-full blur-3xl" />
<img
src="/assets/images/regenerated_image_1779109861747.png"
alt="آزمایشگاه تخصصی تولید مکمل‌های دارویی کانینا آلمان"
className="rounded-[3rem] shadow-2xl relative z-10 grayscale-[10%]"
/>
<div className="absolute -bottom-6 -left-6 bg-canina-blue text-white p-8 rounded-[2rem] shadow-xl z-20">
<div className="text-4xl font-black mb-1 font-lalezar tracking-wide">{getText('quality', "کیفیت")}</div>
<div className="text-xs uppercase tracking-widest font-bold opacity-80 font-vazir">{getText('ultra_pharmaceutical', "استانداردهای فوق‌دارویی")}</div>
</div>
</div>
<div className="relative overflow-hidden rounded-[3rem]">
<div className="absolute -top-10 -right-10 w-40 h-40 bg-canina-blue/5 rounded-full blur-3xl" />
<img
src="/assets/images/regenerated_image_1779109861747.png"
alt="آزمایشگاه تخصصی تولید مکمل‌های دارویی کانینا آلمان"
className="rounded-[3rem] shadow-2xl relative z-10 grayscale-[10%] w-full"
/>
<div className="absolute bottom-4 left-4 sm:bottom-6 sm:left-6 bg-canina-blue text-white p-4 sm:p-6 md:p-8 rounded-[1.5rem] sm:rounded-[2rem] shadow-2xl z-20 max-w-[80%] border border-white/10">
<div className="text-2xl sm:text-4xl font-black mb-1 font-lalezar tracking-wide">{getText('quality', "کیفیت")}</div>
<div className="text-[10px] sm:text-xs uppercase tracking-widest font-bold opacity-90 font-vazir">{getText('ultra_pharmaceutical', "استانداردهای فوق‌دارویی")}</div>
</div>
</div>
<div>
<div className="text-canina-blue text-xs font-bold uppercase tracking-[0.2em] mb-4 font-vazir">
{getText('about_label', "میراث ما از آلمان")}

View File

@ -1,6 +1,6 @@
"use client";
import React from "react";
import { Phone, Mail, MapPin, Instagram, ShieldCheck, Globe } from "lucide-react";
import React, { useState, useEffect } from "react";
import { Phone, Mail, MapPin, Instagram, ShieldCheck, Globe, ArrowUp } from "lucide-react";
import { useSettingsStore } from "../lib/store/settingsStore";
import Link from "next/link";
@ -10,8 +10,38 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
onB2BOpen?: () => void
}) {
const getText = useSettingsStore(state => state.getText);
const [showScroll, setShowScroll] = useState(false);
useEffect(() => {
const checkScroll = () => {
if (window.scrollY > 300) {
setShowScroll(true);
} else {
setShowScroll(false);
}
};
window.addEventListener('scroll', checkScroll);
return () => window.removeEventListener('scroll', checkScroll);
}, []);
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
};
return (
<footer className="bg-medical-gray-900 text-white pt-24 pb-12 font-shabnam" dir="rtl">
<footer className="bg-medical-gray-900 text-white pt-24 pb-12 font-shabnam relative" dir="rtl">
{/* Floating Back-to-Top Button */}
{showScroll && (
<button
onClick={scrollToTop}
className="fixed bottom-8 left-8 z-40 bg-canina-blue text-white p-3.5 rounded-full shadow-2xl hover:bg-canina-dark hover:scale-110 transition-all border border-white/20 group flex items-center gap-2 font-vazir text-xs font-black"
title="بازگشت به بالای صفحه"
>
<ArrowUp className="w-5 h-5 group-hover:-translate-y-1 transition-transform" />
<span className="hidden sm:inline">بازگشت به بالا</span>
</button>
)}
<div className="max-w-7xl mx-auto px-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-16 mb-20">
@ -125,7 +155,11 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
<div className="pt-12 border-t border-white/5 flex flex-col md:flex-row items-center justify-between gap-6 text-[10px] font-bold uppercase tracking-[0.3em] font-shabnam">
<div className="text-slate-400 font-shabnam">{getText('footer_copyright', "© ۲۰۲۶ کانینا ایران. تمامی حقوق محفوظ است.")}</div>
<div className="flex gap-8 font-shabnam text-slate-400">
<div className="flex gap-8 font-shabnam text-slate-400 items-center">
<button onClick={scrollToTop} className="hover:text-white transition-colors flex items-center gap-1 font-bold text-canina-gold">
<ArrowUp className="w-3.5 h-3.5" />
بازگشت به بالای صفحه
</button>
<Link href="/about" className="font-extrabold hover:text-white transition-colors">{getText('footer_about', "درباره ما")}</Link>
<Link href="/contact" className="font-extrabold hover:text-white transition-colors">{getText('footer_contact', "تماس با ما")}</Link>
<Link href="/privacy" className="font-extrabold hover:text-white transition-colors">{getText('footer_privacy', "حریم خصوصی")}</Link>

View File

@ -104,12 +104,12 @@ export default function Header({
</div>
<header className="sticky top-0 z-50 bg-white/95 backdrop-blur-md border-b border-medical-gray-100 shadow-sm">
<div className="max-w-7xl mx-auto h-24 flex items-center justify-between gap-4 px-4 sm:px-6 lg:px-8" dir="rtl">
<div className="flex items-center gap-2">
<div className="max-w-7xl mx-auto h-20 md:h-24 flex items-center justify-between gap-2 sm:gap-4 px-3 sm:px-6 lg:px-8" dir="rtl">
<div className="flex items-center gap-2 min-w-0">
{/* Mobile Menu Toggle */}
<button
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
className="lg:hidden p-2 rounded-xl text-medical-gray-600 hover:bg-medical-gray-50 transition-all"
className="lg:hidden p-2 rounded-xl text-medical-gray-600 hover:bg-medical-gray-50 transition-all flex-shrink-0"
aria-label="منو"
>
{isMobileMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
@ -118,18 +118,18 @@ export default function Header({
{/* Logo Section */}
<Link
href="/"
className="flex-shrink-0 flex items-center gap-3 cursor-pointer group"
className="flex-shrink flex items-center gap-2 sm:gap-3 cursor-pointer group min-w-0"
onClick={() => setIsMobileMenuOpen(false)}
>
<div className="w-12 h-12 bg-canina-blue rounded-2xl flex items-center justify-center text-white font-bold text-2xl group-hover:bg-medical-gray-900 transition-all shadow-xl shadow-canina-blue/20 italic">C</div>
<div className="flex flex-col justify-center gap-1">
<span className="text-canina-blue font-black text-2xl tracking-tighter italic font-sans flex items-center gap-2 leading-none">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-canina-blue rounded-2xl flex items-center justify-center text-white font-bold text-xl sm:text-2xl group-hover:bg-medical-gray-900 transition-all shadow-xl shadow-canina-blue/20 italic flex-shrink-0">C</div>
<div className="flex flex-col justify-center gap-0.5 sm:gap-1 min-w-0">
<span className="text-canina-blue font-black text-lg sm:text-2xl tracking-tighter italic font-sans flex items-center gap-1 sm:gap-2 leading-none">
Canina
<span className="text-sm not-italic font-medium border-r-2 border-medical-gray-200 pr-2 font-vazir">
<span className="text-xs sm:text-sm not-italic font-medium border-r-2 border-medical-gray-200 pr-1.5 sm:pr-2 font-vazir">
{getText('brand_name_fa', "ایران")}
</span>
</span>
<span className="text-[9px] text-medical-gray-400 font-bold uppercase tracking-wider font-vazir leading-none">
<span className="text-[8px] sm:text-[9px] text-medical-gray-400 font-bold uppercase tracking-wider font-vazir leading-none truncate max-w-[140px] sm:max-w-none">
{getText('brand_subtitle', "نماینده رسمی Canina Pharma GmbH آلمان")}
</span>
</div>
@ -217,7 +217,7 @@ export default function Header({
</nav>
{/* Action Area */}
<div className="flex items-center gap-4 flex-shrink-0 justify-end h-16 pl-2">
<div className="flex items-center gap-1.5 sm:gap-4 flex-shrink-0 justify-end h-16 pl-1 sm:pl-2">
{/* Elastic Search */}
<div className="relative flex items-center justify-end z-20">
@ -225,10 +225,10 @@ export default function Header({
{isSearchFocused && (
<motion.div
initial={{ width: 0, opacity: 0 }}
animate={{ width: 320, opacity: 1 }}
animate={{ width: 260, opacity: 1 }}
exit={{ width: 0, opacity: 0 }}
transition={{ type: "spring", damping: 25, stiffness: 220 }}
className="absolute right-0 top-1/2 -translate-y-1/2 bg-white border border-canina-blue/30 border-l rounded-2xl shadow-xl shadow-canina-blue/5 overflow-hidden h-12 flex items-center pr-12 pl-4 z-25"
className="absolute right-0 top-1/2 -translate-y-1/2 bg-white border border-canina-blue/30 border-l rounded-2xl shadow-xl shadow-canina-blue/5 overflow-hidden h-10 sm:h-12 flex items-center pr-10 pl-3 z-25"
>
<form onSubmit={handleSearch} className="w-full flex items-center">
<input
@ -237,9 +237,9 @@ export default function Header({
value={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
onBlur={() => !searchQuery && setIsSearchFocused(false)}
placeholder="جستجوی محصولات، مقالات سلامت و غیره…"
placeholder="جستجو…"
dir="rtl"
className="w-full bg-transparent py-2 pr-4 text-[12px] font-black outline-none font-vazir text-medical-gray-900 text-right placeholder:text-medical-gray-400 placeholder:text-right"
className="w-full bg-transparent py-2 pr-2 text-[12px] font-black outline-none font-vazir text-medical-gray-900 text-right placeholder:text-medical-gray-400 placeholder:text-right"
/>
<input type="submit" className="hidden" />
</form>
@ -250,7 +250,7 @@ export default function Header({
<HeaderButton
variant={isSearchFocused ? "primary" : "secondary"}
className={cn(
"w-12 h-12 transition-all duration-300",
"w-10 h-10 sm:w-12 sm:h-12 transition-all duration-300",
isSearchFocused
? "z-30 bg-canina-blue text-white rounded-r-2xl rounded-l-none border border-canina-blue border-l-0 shadow-none"
: "rounded-2xl"
@ -264,45 +264,45 @@ export default function Header({
}
}}
>
<Search className={cn("w-5 h-5", isSearchFocused ? "text-white" : "text-canina-blue")} />
<Search className={cn("w-4 h-4 sm:w-5 sm:h-5", isSearchFocused ? "text-white" : "text-canina-blue")} />
</HeaderButton>
</div>
<div className="flex gap-2 items-center h-12">
<div className="flex gap-1.5 sm:gap-2 items-center h-12">
{isLoggedIn ? (
<div className="flex items-center h-full gap-2 p-1.5 bg-medical-gray-50/50 border border-medical-gray-100 rounded-3xl">
<div className="flex items-center h-full gap-1.5 sm:gap-2 p-1 bg-medical-gray-50/50 border border-medical-gray-100 rounded-3xl">
{/* User Name (Direct link to dashboard) */}
<div
className="flex items-center gap-2.5 px-4 py-2 hover:bg-white rounded-2xl cursor-pointer transition-all border border-transparent hover:border-medical-gray-200"
className="flex items-center gap-1.5 sm:gap-2.5 px-2.5 sm:px-4 py-2 hover:bg-white rounded-2xl cursor-pointer transition-all border border-transparent hover:border-medical-gray-200"
onClick={() => onNavigate("user-dashboard")}
>
<User className="w-5 h-5 text-canina-blue" />
<span className="text-[14px] font-black font-vazir text-medical-gray-900 leading-none">
<User className="w-4 h-4 sm:w-5 sm:h-5 text-canina-blue" />
<span className="text-[12px] sm:text-[14px] font-black font-vazir text-medical-gray-900 leading-none">
{profile.firstName}
</span>
</div>
{/* Separator Line */}
<div className="w-[1.5px] h-5 bg-medical-gray-200" />
<div className="w-[1.5px] h-4 sm:h-5 bg-medical-gray-200" />
{/* Pet Name & Switcher */}
<div className="relative h-full flex items-center" ref={petMenuRef}>
<div
className={cn(
"flex items-center gap-2.5 px-4 py-2 rounded-2xl transition-all cursor-pointer",
"flex items-center gap-1.5 sm:gap-2.5 px-2.5 sm:px-4 py-2 rounded-2xl transition-all cursor-pointer",
isPetSwitcherOpen ? "bg-canina-blue text-white shadow-lg shadow-canina-blue/20" : "text-canina-blue hover:bg-white"
)}
onClick={() => setIsPetSwitcherOpen(!isPetSwitcherOpen)}
>
{activePet?.type === "گربه" ? (
<Cat className={cn("w-5 h-5", isPetSwitcherOpen ? "text-white" : "text-canina-blue/60")} />
<Cat className={cn("w-4 h-4 sm:w-5 sm:h-5", isPetSwitcherOpen ? "text-white" : "text-canina-blue/60")} />
) : (
<Dog className={cn("w-5 h-5", isPetSwitcherOpen ? "text-white" : "text-canina-blue/60")} />
<Dog className={cn("w-4 h-4 sm:w-5 sm:h-5", isPetSwitcherOpen ? "text-white" : "text-canina-blue/60")} />
)}
<span className={cn("text-[14px] font-black font-vazir leading-none", isPetSwitcherOpen ? "text-white" : "text-canina-blue")}>
<span className={cn("text-[12px] sm:text-[14px] font-black font-vazir leading-none", isPetSwitcherOpen ? "text-white" : "text-canina-blue")}>
{activePet?.name || "بدون پت"}
</span>
<ChevronDown className={cn("w-4 h-4 transition-transform", isPetSwitcherOpen ? "rotate-180" : "")} />
<ChevronDown className={cn("w-3.5 h-3.5 sm:w-4 sm:h-4 transition-transform", isPetSwitcherOpen ? "rotate-180" : "")} />
</div>
<AnimatePresence>
@ -391,22 +391,23 @@ export default function Header({
<HeaderButton
variant="outline"
layout="row"
className="px-6 h-12 text-sm font-black flex items-center justify-center"
className="px-3 sm:px-6 h-10 sm:h-12 text-xs sm:text-sm font-black flex items-center justify-center"
onClick={() => setIsAuthModalOpen(true)}
icon={<LogIn className="w-5 h-5 text-canina-blue" />}
icon={<LogIn className="w-4 h-4 sm:w-5 sm:h-5 text-canina-blue" />}
>
{getText('nav_login', "ورود / ثبت‌نام")}
<span className="hidden xs:inline">{getText('nav_login', "ورود / ثبت‌نام")}</span>
<span className="xs:hidden">ورود</span>
</HeaderButton>
)}
<HeaderButton
variant="primary"
className="w-16 h-12"
className="w-12 sm:w-16 h-10 sm:h-12"
onClick={onCartOpen}
badge={getTotalItems()}
icon={<ShoppingBag className="w-6 h-6" />}
icon={<ShoppingBag className="w-5 h-5 sm:w-6 sm:h-6" />}
>
<div className="text-[8px] font-black tracking-tight whitespace-nowrap mt-0.5">{getText('nav_cart', "سبد خرید")}</div>
<div className="hidden sm:block text-[8px] font-black tracking-tight whitespace-nowrap mt-0.5">{getText('nav_cart', "سبد خرید")}</div>
</HeaderButton>
</div>
</div>

View File

@ -168,46 +168,46 @@ export default function Hero({ banners = [] }: { banners?: any[] }) {
</div>
</div>
{/* Stats - Centered, full-width row under Hero content to decrease cognitive load */}
<div className="max-w-7xl mx-auto px-4 relative">
{/* 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-1 md:grid-cols-3 gap-8 py-10 border-t border-medical-gray-150"
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-3xl p-6 flex items-center gap-6 group hover:shadow-xl hover:shadow-canina-blue/5 transition-all">
<div className="w-14 h-14 bg-white 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">
<Calendar className="w-7 h-7" />
<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="text-right">
<div className="text-3xl font-black text-canina-blue font-vazir leading-none">۱۹۸۴</div>
<div className="text-xs text-medical-gray-500 font-extrabold uppercase tracking-tight mt-2 font-vazir">{getText('hero_stat_founded', "سال تاسیس برند در آلمان")}</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">{getText('hero_stat_founded', "سال تاسیس برند")}</div>
</div>
</div>
{/* Stat 2: Active Agencies */}
<div className="bg-medical-gray-50/50 border border-medical-gray-100 rounded-3xl p-6 flex items-center gap-6 group hover:shadow-xl hover:shadow-canina-blue/5 transition-all">
<div className="w-14 h-14 bg-white 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">
<Globe className="w-7 h-7" />
<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="text-right">
<div className="flex items-baseline">
<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-xs text-medical-gray-500 font-extrabold uppercase tracking-tight mt-2 font-vazir">{getText('hero_stat_agencies', "نمایندگی فعال جهانی")}</div>
<div className="text-[9px] sm:text-xs text-medical-gray-500 font-extrabold uppercase tracking-tight mt-1 sm:mt-2 font-vazir">{getText('hero_stat_agencies', "نمایندگی فعال")}</div>
</div>
</div>
{/* Stat 3: German Formula */}
<div className="bg-medical-gray-50/50 border border-medical-gray-100 rounded-3xl p-6 flex items-center gap-6 group hover:shadow-xl hover:shadow-canina-blue/5 transition-all">
<div className="w-14 h-14 bg-white 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">
<ShieldCheck className="w-7 h-7" />
<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="text-right">
<div className="text-3xl font-black text-canina-blue font-vazir leading-none">۱۰۰٪</div>
<div className="text-xs text-medical-gray-500 font-extrabold uppercase tracking-tight mt-2 font-vazir">{getText('hero_stat_german_formula', "فرمولاسیون علمی اختصاصی")}</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">{getText('hero_stat_german_formula', "فرمول آلمانی")}</div>
</div>
</div>
</motion.div>