feat(ui): refine desktop sticky buy box, redesign blog newsletter CTA, enhance wiki product cards padding, add symptom search & active filters bar
This commit is contained in:
parent
c7b944f5c4
commit
f367499a5c
@ -239,6 +239,7 @@ export default function ArchivePage({
|
||||
const [page, setPage] = useState(1);
|
||||
const [meta, setMeta] = useState({ total: 0, lastPage: 1 });
|
||||
|
||||
const [symptomSearch, setSymptomSearch] = useState("");
|
||||
const [categories, setCategories] = useState<{ id: string; label: string; icon: React.ReactNode }[]>([]);
|
||||
const [symptoms, setSymptoms] = useState<string[]>([]);
|
||||
|
||||
@ -462,7 +463,7 @@ export default function ArchivePage({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Symptoms Pill Tags */}
|
||||
{/* Symptoms Pill Tags with Search Field */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest">جستجو بر اساس علائم</span>
|
||||
@ -475,21 +476,32 @@ export default function ArchivePage({
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5 max-h-52 overflow-y-auto scrollbar-thin scrollbar-thumb-medical-gray-200 scrollbar-track-transparent pr-0.5">
|
||||
<div className="relative mb-3">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="جستجوی علائم..."
|
||||
value={symptomSearch}
|
||||
onChange={(e) => setSymptomSearch(e.target.value)}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 text-xs outline-none focus:border-canina-blue font-vazir"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5 max-h-48 overflow-y-auto scrollbar-thin scrollbar-thumb-medical-gray-200 scrollbar-track-transparent pr-0.5">
|
||||
{symptoms.length === 0 ? (
|
||||
<span className="text-[10px] text-medical-gray-400">در حال بارگذاری...</span>
|
||||
) : symptoms.map(s => (
|
||||
<button
|
||||
key={s}
|
||||
onClick={() => toggleSymptom(s)}
|
||||
className={`px-2.5 py-1 rounded-full text-[10px] font-bold transition-all border whitespace-nowrap ${activeSymptoms.includes(s)
|
||||
? 'bg-canina-blue border-canina-blue text-white shadow-sm shadow-canina-blue/30'
|
||||
: 'bg-medical-gray-50 border-medical-gray-200 text-medical-gray-500 hover:border-canina-blue/40 hover:text-canina-blue'
|
||||
}`}
|
||||
>
|
||||
{s}
|
||||
</button>
|
||||
))}
|
||||
) : symptoms
|
||||
.filter(s => s.toLowerCase().includes(symptomSearch.toLowerCase()))
|
||||
.map(s => (
|
||||
<button
|
||||
key={s}
|
||||
onClick={() => toggleSymptom(s)}
|
||||
className={`px-2.5 py-1 rounded-full text-[10px] font-bold transition-all border whitespace-nowrap ${activeSymptoms.includes(s)
|
||||
? 'bg-canina-blue border-canina-blue text-white shadow-sm shadow-canina-blue/30'
|
||||
: 'bg-medical-gray-50 border-medical-gray-200 text-medical-gray-500 hover:border-canina-blue/40 hover:text-canina-blue'
|
||||
}`}
|
||||
>
|
||||
{s}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -506,7 +518,7 @@ export default function ArchivePage({
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex-1 relative">
|
||||
<div className="flex flex-col md:flex-row items-center justify-between mb-8 gap-4">
|
||||
<div className="flex flex-col md:flex-row items-center justify-between mb-6 gap-4">
|
||||
<h2 className="text-3xl font-black text-medical-gray-900">کاتولوگ دارویی <span className="text-canina-blue">Canina</span></h2>
|
||||
<div className="relative w-full md:w-80">
|
||||
<Search className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400" />
|
||||
@ -520,6 +532,43 @@ export default function ArchivePage({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Active Filters Bar with X Dismiss Cross Buttons */}
|
||||
{(selectedCategory !== "all" || selectedPet !== "all" || activeSymptoms.length > 0 || searchQuery) && (
|
||||
<div className="flex flex-wrap items-center gap-2 mb-6 bg-white p-4 rounded-2xl border border-medical-gray-200 shadow-sm font-vazir" dir="rtl">
|
||||
<span className="text-xs font-black text-medical-gray-400 ml-2">فیلترهای فعال:</span>
|
||||
{selectedCategory !== "all" && (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
|
||||
{CATEGORY_LABELS[selectedCategory] || selectedCategory}
|
||||
<button onClick={() => setSelectedCategory("all")} className="hover:text-red-500 text-sm leading-none">✕</button>
|
||||
</span>
|
||||
)}
|
||||
{selectedPet !== "all" && (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
|
||||
پت: {selectedPet}
|
||||
<button onClick={() => setSelectedPet("all")} className="hover:text-red-500 text-sm leading-none">✕</button>
|
||||
</span>
|
||||
)}
|
||||
{activeSymptoms.map(sym => (
|
||||
<span key={sym} className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
|
||||
علائم: {sym}
|
||||
<button onClick={() => toggleSymptom(sym)} className="hover:text-red-500 text-sm leading-none">✕</button>
|
||||
</span>
|
||||
))}
|
||||
{searchQuery && (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
|
||||
جستجو: {searchQuery}
|
||||
<button onClick={() => setSearchQuery("")} className="hover:text-red-500 text-sm leading-none">✕</button>
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
onClick={() => { setSelectedCategory("all"); setSelectedPet("all"); setActiveSymptoms([]); setSearchQuery(""); }}
|
||||
className="text-xs font-bold text-red-500 hover:underline mr-auto"
|
||||
>
|
||||
حذف همه فیلترها
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<AnimatePresence mode="wait">
|
||||
{isUpdating ? (
|
||||
<div key="skeleton" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||
|
||||
@ -258,22 +258,29 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
|
||||
))}
|
||||
|
||||
{/* Newsletter / CTA Box */}
|
||||
<div className="bg-canina-blue rounded-[2.5rem] sm:rounded-[3rem] p-6 sm:p-10 text-white relative overflow-hidden flex flex-col justify-center text-center sm:text-right font-vazir">
|
||||
<div className="absolute top-0 right-0 p-8 opacity-20 pointer-events-none">
|
||||
<Sparkles className="w-24 h-24" />
|
||||
<div className="bg-canina-blue rounded-[2.5rem] sm:rounded-[3.5rem] p-8 sm:p-12 text-white relative overflow-hidden flex flex-col md:flex-row items-center justify-between gap-8 font-vazir shadow-2xl">
|
||||
<div className="absolute top-0 right-0 p-8 opacity-10 pointer-events-none">
|
||||
<div className="w-48 h-48 bg-white/20 rounded-full blur-3xl" />
|
||||
</div>
|
||||
<h3 className="text-2xl sm:text-3xl font-black mb-4 italic font-lalezar">مشترک خبرنامه علمی شوید</h3>
|
||||
<p className="text-white/80 mb-6 font-medium leading-relaxed text-xs sm:text-sm font-shabnam">
|
||||
ماهانه یک ایمیل حاوی مهمترین نکات سلامت پتها و کدهای تخفیف اختصاصی دریافت کنید.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-2 max-w-md mx-auto sm:mx-0">
|
||||
<div className="flex items-center gap-6 relative z-10 text-right">
|
||||
<div className="w-16 h-16 bg-white/10 backdrop-blur-md rounded-3xl flex items-center justify-center text-white font-black text-3xl italic shadow-inner flex-shrink-0">
|
||||
C
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl sm:text-3xl font-black mb-2 italic font-vazir">مشترک خبرنامه علمی شوید</h3>
|
||||
<p className="text-white/80 font-medium text-xs sm:text-sm font-vazir max-w-lg">
|
||||
ماهانه یک ایمیل حاوی مهمترین نکات سلامت پتها و کدهای تخفیف اختصاصی دریافت کنید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row gap-3 w-full md:w-auto relative z-10">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="آدرس ایمیل شما"
|
||||
className="flex-1 bg-white/10 border border-white/20 rounded-xl px-4 py-3 text-xs outline-none focus:bg-white/20 placeholder:text-white/50 text-white"
|
||||
className="bg-white/10 border border-white/20 rounded-2xl px-5 py-3.5 text-xs outline-none focus:bg-white/20 placeholder:text-white/50 text-white w-full sm:w-64 font-vazir"
|
||||
/>
|
||||
<button className="bg-white text-canina-blue px-6 py-3 rounded-xl font-black text-xs hover:bg-slate-100 transition-all whitespace-nowrap shadow-md">
|
||||
عضویت
|
||||
<button className="bg-white text-canina-blue px-8 py-3.5 rounded-2xl font-black text-xs hover:bg-canina-gold hover:text-canina-dark transition-all whitespace-nowrap shadow-lg">
|
||||
عضویت در خبرنامه
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -231,21 +231,29 @@ export default function IngredientWiki() {
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
className="bg-medical-gray-100 rounded-[4rem] p-12 relative overflow-hidden"
|
||||
className="bg-medical-gray-100/80 rounded-[3rem] p-8 sm:p-10 border border-medical-gray-200/60 relative overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 right-0 p-8">
|
||||
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-[0.3em]">موجود در محصولات</div>
|
||||
<div className="flex items-center justify-between mb-8 pb-4 border-b border-medical-gray-200/60">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-canina-blue animate-pulse" />
|
||||
<h4 className="text-xs sm:text-sm font-black text-medical-gray-900 font-vazir">موجود در محصولات کاتالوگ</h4>
|
||||
</div>
|
||||
<span className="text-[10px] font-black text-canina-blue bg-canina-blue/10 px-3 py-1 rounded-full font-vazir">
|
||||
{hasIngredient.length} محصول
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 relative z-10">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5 relative z-10">
|
||||
{hasIngredient.length > 0 ? hasIngredient.map(p => (
|
||||
<Link
|
||||
key={p.id}
|
||||
href={`/shop/${p.slug || p.id}`}
|
||||
className="bg-white rounded-[2.5rem] p-6 shadow-xl hover:scale-105 transition-transform cursor-pointer group block"
|
||||
className="bg-white rounded-[2rem] p-5 shadow-lg border border-medical-gray-200/70 hover:border-canina-blue/40 hover:shadow-xl hover:scale-[1.03] transition-all cursor-pointer group flex flex-col justify-between"
|
||||
>
|
||||
<img src={p.image} alt={p.name} className="w-24 h-24 object-contain mx-auto mb-4" referrerPolicy="no-referrer" />
|
||||
<h4 className="text-sm font-black text-center text-medical-gray-900 group-hover:text-canina-blue transition-colors px-2">{p.name}</h4>
|
||||
<div className="aspect-square bg-medical-gray-50 rounded-2xl p-4 mb-4 flex items-center justify-center">
|
||||
<img src={p.image} alt={p.name} className="max-h-24 w-auto object-contain group-hover:scale-110 transition-transform duration-500" referrerPolicy="no-referrer" />
|
||||
</div>
|
||||
<h4 className="text-xs font-black text-center text-medical-gray-900 group-hover:text-canina-blue transition-colors px-1 leading-snug font-vazir">{p.name}</h4>
|
||||
</Link>
|
||||
)) : (
|
||||
<div className="col-span-full py-8 text-center">
|
||||
|
||||
@ -585,7 +585,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
||||
</div>
|
||||
|
||||
{/* Sticky Sidebar (Clean Buy Box) - Hidden on mobile as mobile floating buy bar is active */}
|
||||
<div className="hidden lg:block lg:col-span-4 lg:sticky lg:top-28 space-y-8">
|
||||
<div className="hidden lg:block lg:col-span-4 lg:sticky lg:top-36 space-y-8">
|
||||
<div className="bg-white rounded-[2.5rem] border-2 border-medical-gray-100 p-8 shadow-2xl relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-canina-blue/5 rounded-full -mr-12 -mt-12" />
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user