Polish header icon alignment and banner hover overlays.

Align cart with search/profile controls and show banner slot text only on hover.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-30 10:58:28 +03:30
co-authored by Cursor
parent 9e2dc2c61d
commit 3576052f9d
5 changed files with 29 additions and 22 deletions
+8 -2
View File
@@ -56,11 +56,17 @@ const categoryFallbacks: SlotMediaItem[] = [
]; ];
const bannerFallbacks: SlotMediaItem[] = [ const bannerFallbacks: SlotMediaItem[] = [
{ id: "banner-1", image: "/images/banner-1.png", href: "#" }, {
id: "banner-1",
image: "/images/banner-1.png",
href: "/products",
title: "فروش ویژه",
titleEn: "SPECIAL SALE",
},
{ {
id: "banner-2", id: "banner-2",
image: "/images/console-cat-4.jpg", image: "/images/console-cat-4.jpg",
href: "#", href: "/products",
title: "کلکسیون میز کنسول", title: "کلکسیون میز کنسول",
titleEn: "NEW COLLECTION", titleEn: "NEW COLLECTION",
}, },
+13 -12
View File
@@ -10,13 +10,9 @@ export default function BannerRow({ items, aspectRatio }: BannerRowProps) {
return ( return (
<section className="mx-auto grid max-w-6xl grid-cols-1 gap-6 px-4 py-4 sm:px-6 md:grid-cols-2 lg:px-8"> <section className="mx-auto grid max-w-6xl grid-cols-1 gap-6 px-4 py-4 sm:px-6 md:grid-cols-2 lg:px-8">
{items.map((banner) => { {items.map((banner) => {
const hasOverlay = Boolean(banner.title || banner.titleEn || banner.text); const hasContent = Boolean(banner.title || banner.titleEn || banner.text);
const media = ( const media = (
<div <div className="group relative block overflow-hidden rounded-2xl bg-neutral-100 shadow-sm">
className={`group relative block overflow-hidden rounded-2xl shadow-sm ${
hasOverlay ? "" : "bg-white"
}`}
>
<SlotMedia <SlotMedia
src={banner.image} src={banner.image}
href={undefined} href={undefined}
@@ -26,16 +22,21 @@ export default function BannerRow({ items, aspectRatio }: BannerRowProps) {
className={!aspectRatio ? "block h-56 w-full sm:h-72" : "block w-full"} className={!aspectRatio ? "block h-56 w-full sm:h-72" : "block w-full"}
imgClassName="absolute inset-0 h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" imgClassName="absolute inset-0 h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
/> />
{hasOverlay ? ( {hasContent ? (
<div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 bg-black/40 text-center text-white"> <div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 bg-white/0 text-center opacity-0 transition-all duration-300 group-hover:bg-white/80 group-hover:opacity-100">
{banner.titleEn ? ( {banner.titleEn ? (
<p className="text-xs tracking-[0.3em]" style={{ fontFamily: "var(--font-montserrat)" }}> <p
className="text-xs tracking-[0.3em] text-primary"
style={{ fontFamily: "var(--font-montserrat)" }}
>
{banner.titleEn} {banner.titleEn}
</p> </p>
) : null} ) : null}
{banner.title ? <h3 className="text-2xl font-bold">{banner.title}</h3> : null} {banner.title ? (
{banner.text ? <p className="text-sm">{banner.text}</p> : null} <h3 className="text-2xl font-bold text-neutral-800">{banner.title}</h3>
<span className="mt-2 rounded-full border border-white/70 px-5 py-2 text-sm font-medium transition-colors group-hover:bg-white group-hover:text-neutral-900"> ) : null}
{banner.text ? <p className="text-sm text-neutral-600">{banner.text}</p> : null}
<span className="mt-2 rounded-full border border-primary/70 px-5 py-2 text-sm font-medium text-primary transition-colors group-hover:bg-primary group-hover:text-white">
مشاهده محصولات مشاهده محصولات
</span> </span>
</div> </div>
+4 -4
View File
@@ -17,14 +17,14 @@ export default function CartPopover() {
useClickOutside(ref, () => setOpen(false)); useClickOutside(ref, () => setOpen(false));
return ( return (
<div className="relative" ref={ref}> <div className="relative flex items-center" ref={ref}>
<button <button
type="button" type="button"
aria-label="سبد خرید" aria-label="سبد خرید"
onClick={() => setOpen((v) => !v)} onClick={() => setOpen((v) => !v)}
className="relative text-neutral-600 transition-colors hover:text-primary" className="relative inline-flex h-9 w-9 items-center justify-center text-neutral-600 transition-colors hover:text-primary"
> >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" className="h-5 w-5"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" className="h-5 w-5 translate-y-px">
<path <path
d="M3 4h2l1.4 11.2A2 2 0 0 0 8.4 17H18a2 2 0 0 0 2-1.6L21.5 8H6" d="M3 4h2l1.4 11.2A2 2 0 0 0 8.4 17H18a2 2 0 0 0 2-1.6L21.5 8H6"
stroke="currentColor" stroke="currentColor"
@@ -36,7 +36,7 @@ export default function CartPopover() {
<circle cx="17.5" cy="20.5" r="1.3" fill="currentColor" /> <circle cx="17.5" cy="20.5" r="1.3" fill="currentColor" />
</svg> </svg>
{itemCount > 0 ? ( {itemCount > 0 ? (
<span className="absolute -top-2 -left-2 flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-bold text-white"> <span className="absolute top-0 left-0 flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-bold text-white">
{itemCount} {itemCount}
</span> </span>
) : null} ) : null}
+1 -1
View File
@@ -52,7 +52,7 @@ export default async function Header() {
<div className="flex items-center gap-5"> <div className="flex items-center gap-5">
<button <button
aria-label="جستجو" aria-label="جستجو"
className="text-neutral-600 transition-colors hover:text-primary" className="inline-flex h-9 w-9 items-center justify-center text-neutral-600 transition-colors hover:text-primary"
> >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" className="h-5 w-5"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" className="h-5 w-5">
<circle cx="11" cy="11" r="7" stroke="currentColor" strokeWidth="1.8" /> <circle cx="11" cy="11" r="7" stroke="currentColor" strokeWidth="1.8" />
+3 -3
View File
@@ -66,7 +66,7 @@ export default function ProfileMenu() {
return ( return (
<a <a
href={loginUrl || CUSTOMER_PORTAL_URL} href={loginUrl || CUSTOMER_PORTAL_URL}
className="flex items-center gap-1.5 text-sm font-medium text-neutral-700 transition-colors hover:text-primary" className="inline-flex h-9 items-center gap-1.5 text-sm font-medium text-neutral-700 transition-colors hover:text-primary"
aria-label="ورود" aria-label="ورود"
> >
<UserIcon /> <UserIcon />
@@ -76,11 +76,11 @@ export default function ProfileMenu() {
} }
return ( return (
<div className="relative" ref={ref}> <div className="relative flex items-center" ref={ref}>
<button <button
type="button" type="button"
onClick={() => setOpen((v) => !v)} onClick={() => setOpen((v) => !v)}
className="flex items-center gap-1.5 text-sm font-medium text-neutral-700 transition-colors hover:text-primary" className="inline-flex h-9 items-center gap-1.5 text-sm font-medium text-neutral-700 transition-colors hover:text-primary"
aria-expanded={open} aria-expanded={open}
aria-haspopup="menu" aria-haspopup="menu"
> >