Redesign header icons/account-cart chip, light footer, fix sticky-footer gap
- New shared SVG icon set (src/components/ui/icons.tsx): Menu, User, Cart, Close, ChevronLeft — replaces emoji (☰ 👤 🛒 ✕) across the header, and the literal "←" text arrow on every "view more"-style link (SectionTitle's action, the mega-menu link, BlogCarousel's "ادامه مطلب"). - Header desktop account/cart area redesigned as a borderless chip: cart icon button (right) + divider + account icon-badge/two-line "حساب کاربری / ورود/ثبتنام" (left), matching a supplied reference. Got the RTL DOM order backwards on the first pass (cart needs to be first in DOM to render rightmost) and corrected it. - Header logo: -10px (was already doubled from an earlier request). - Footer: background is now bg-[#9a21291a] (exact hex given, not a token substitute) with black text throughout instead of solid dark-red/white; footer logo doubled; the meshkee-credit logo gets brightness-0 so the white source asset stays visible on the new light background. - Fixed a real layout bug: <main> had no flex-1, so on any page shorter than the viewport the footer stuck to the content instead of the bottom of the screen, leaving a gap of bare background beneath it. Standard sticky-footer flex fix. - CONTEXT.md: documented the icon set, the account/cart chip's RTL DOM ordering (to stop this regressing again), and the footer's new color scheme + the flex-1 fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7a78adc7f3
commit
d090f57540
+41
@@ -180,6 +180,28 @@ persistent memory as "for all the user's sites", not just this one)
|
|||||||
in the array — first DOM child renders rightmost under `dir="rtl"`).
|
in the array — first DOM child renders rightmost under `dir="rtl"`).
|
||||||
- Category tile images: 110px, no border, no border-radius
|
- Category tile images: 110px, no border, no border-radius
|
||||||
(`FeaturedCategories.tsx`).
|
(`FeaturedCategories.tsx`).
|
||||||
|
- **No emoji as icons** — `src/components/ui/icons.tsx` has the shared
|
||||||
|
light/outline SVG set (`MenuIcon`, `UserIcon`, `CartIcon`, `CloseIcon`,
|
||||||
|
`ChevronLeftIcon`), 24x24 viewBox, `stroke="currentColor"`. Use these
|
||||||
|
instead of characters like "☰"/"👤"/"🛒"/"✕". Every "view more"-style
|
||||||
|
link/button (`SectionTitle`'s `action`, the mega-menu's "مشاهده همه",
|
||||||
|
`BlogCarousel`'s "ادامه مطلب") uses `ChevronLeftIcon`, not a literal "←"
|
||||||
|
character — keep new ones consistent with that.
|
||||||
|
- **Header account/cart cluster** (`Header.tsx`, desktop only —
|
||||||
|
`hidden ... sm:flex`): a borderless `bg-surface` chip holding, in this
|
||||||
|
exact DOM order, `CartButton`, a divider, then the login link. That DOM
|
||||||
|
order is deliberate and easy to get backwards: under `dir="rtl"` the
|
||||||
|
first DOM child renders rightmost, so cart-first-in-DOM is what actually
|
||||||
|
puts the cart icon on the visual **right** and the login block on the
|
||||||
|
**left** (this was built backwards once and corrected). Same rule inside
|
||||||
|
the login link itself — the icon badge comes before the two-line text in
|
||||||
|
DOM so the icon renders right of the text. Neither `CartButton` nor this
|
||||||
|
wrapper has a border (removed on request — don't reintroduce one).
|
||||||
|
`CartButton` is a fixed 44px (`h-11 w-11`) icon-only square everywhere it
|
||||||
|
renders (also stands alone, un-wrapped, below `sm`); its unread-count
|
||||||
|
badge sits at `-top-1.5 -right-1.5`, not the product-card cart badge's
|
||||||
|
`-left-1.5` — don't copy that positioning between the two, they're
|
||||||
|
intentionally different corners for different-looking buttons.
|
||||||
|
|
||||||
## Static-image slots
|
## Static-image slots
|
||||||
|
|
||||||
@@ -274,6 +296,25 @@ render a `<link rel="icon">` and browsers aren't guaranteed to prefer the
|
|||||||
second one, so keeping both was silently serving the stale static icon.
|
second one, so keeping both was silently serving the stale static icon.
|
||||||
Don't add `app/favicon.ico` (or `public/favicon.ico`) back.
|
Don't add `app/favicon.ico` (or `public/favicon.ico`) back.
|
||||||
|
|
||||||
|
## Footer: light background, black text, sticky to viewport bottom
|
||||||
|
|
||||||
|
The footer is `bg-[#9a21291a]` (a ~10%-opacity red-tint, given as an exact
|
||||||
|
hex by the user — not swapped for the closest design-token color) with
|
||||||
|
black text throughout (`text-black`, `/70`, `/50`, `/10`, `/20` opacity
|
||||||
|
steps) — it used to be a solid dark-red block with white text; don't revert
|
||||||
|
to that. The footer logo (`logoDarkUrl ?? logoUrl`) is `h-[72px]`, doubled
|
||||||
|
from its original size on request. Because `public/images/meshkee-logo-
|
||||||
|
white.png` (the credit-widget logo below) is a solid-white asset, it gets
|
||||||
|
`brightness-0` on this light background to render as a black silhouette
|
||||||
|
instead of invisible white-on-near-white — the same `opacity-60 →
|
||||||
|
group-hover:opacity-100` fade still applies on top of that.
|
||||||
|
|
||||||
|
`<main>` has `flex-1` in `layout.tsx` (`body` is `flex flex-col`) so the
|
||||||
|
footer sits flush at the bottom of the viewport on short pages instead of
|
||||||
|
leaving a gap of bare `background` color beneath it — this is the standard
|
||||||
|
sticky-footer flex pattern. Don't remove `flex-1` from `main` without
|
||||||
|
re-checking a short page (e.g. `/contact`) for that gap coming back.
|
||||||
|
|
||||||
## Footer: Meshkee credit widget
|
## Footer: Meshkee credit widget
|
||||||
|
|
||||||
The footer's bottom-right link ("Designed And Developed By Meshkee
|
The footer's bottom-right link ("Designed And Developed By Meshkee
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ export default async function RootLayout({ children }: LayoutProps<"/">) {
|
|||||||
<Providers>
|
<Providers>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<Header categoryTree={categoryTree} categories={categories} logoUrl={businessInfo?.logoUrl} />
|
<Header categoryTree={categoryTree} categories={categories} logoUrl={businessInfo?.logoUrl} />
|
||||||
<main>{children}</main>
|
<main className="flex-1">{children}</main>
|
||||||
<Footer businessInfo={businessInfo} categories={categories} />
|
<Footer businessInfo={businessInfo} categories={categories} />
|
||||||
</Providers>
|
</Providers>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useCart } from "@/context/CartContext";
|
import { useCart } from "@/context/CartContext";
|
||||||
|
import { CartIcon } from "@/components/ui/icons";
|
||||||
|
|
||||||
export function CartButton() {
|
export function CartButton() {
|
||||||
const { itemCount, openPopup } = useCart();
|
const { itemCount, openPopup } = useCart();
|
||||||
@@ -9,12 +10,12 @@ export function CartButton() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={openPopup}
|
onClick={openPopup}
|
||||||
className="relative flex items-center gap-1.5 rounded-lg border border-border px-3 py-2 transition-colors hover:border-red hover:text-red"
|
aria-label="سبد خرید"
|
||||||
|
className="relative flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface text-foreground transition-colors hover:text-red"
|
||||||
>
|
>
|
||||||
<span aria-hidden>🛒</span>
|
<CartIcon className="h-5 w-5" />
|
||||||
<span className="hidden sm:inline">سبد خرید</span>
|
|
||||||
{itemCount > 0 && (
|
{itemCount > 0 && (
|
||||||
<span className="absolute -top-1.5 -left-1.5 flex h-5 min-w-5 items-center justify-center rounded-full bg-red px-1 text-[10px] font-bold text-white">
|
<span className="absolute -top-1.5 -right-1.5 flex h-5 min-w-5 items-center justify-center rounded-full bg-red px-1 text-[10px] font-bold text-white">
|
||||||
{itemCount}
|
{itemCount}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Placeholder } from "@/components/ui/Placeholder";
|
|||||||
import { SectionTitle } from "@/components/ui/SectionTitle";
|
import { SectionTitle } from "@/components/ui/SectionTitle";
|
||||||
import { Carousel } from "@/components/ui/Carousel";
|
import { Carousel } from "@/components/ui/Carousel";
|
||||||
import { EmptyState } from "@/components/ui/EmptyState";
|
import { EmptyState } from "@/components/ui/EmptyState";
|
||||||
|
import { ChevronLeftIcon } from "@/components/ui/icons";
|
||||||
import type { BlogSummary } from "@/lib/meshkee";
|
import type { BlogSummary } from "@/lib/meshkee";
|
||||||
|
|
||||||
function formatDate(iso?: string) {
|
function formatDate(iso?: string) {
|
||||||
@@ -50,8 +51,9 @@ export function BlogCarousel({ posts }: { posts: BlogSummary[] }) {
|
|||||||
{post.abstract}
|
{post.abstract}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<span className="mt-3 block text-xs font-medium text-red">
|
<span className="mt-3 flex items-center gap-1 text-xs font-medium text-red">
|
||||||
ادامه مطلب ←
|
ادامه مطلب
|
||||||
|
<ChevronLeftIcon className="h-3.5 w-3.5" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function Footer({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="border-t border-red-dark/20 bg-red-dark text-white">
|
<footer className="border-t border-red-dark/15 bg-[#9a21291a] text-black">
|
||||||
<div className="mx-auto max-w-7xl px-4 py-12">
|
<div className="mx-auto max-w-7xl px-4 py-12">
|
||||||
<div className="grid gap-8 md:grid-cols-4">
|
<div className="grid gap-8 md:grid-cols-4">
|
||||||
<div>
|
<div>
|
||||||
@@ -37,7 +37,7 @@ export function Footer({
|
|||||||
<img
|
<img
|
||||||
src={businessInfo.logoDarkUrl ?? businessInfo.logoUrl ?? undefined}
|
src={businessInfo.logoDarkUrl ?? businessInfo.logoUrl ?? undefined}
|
||||||
alt={businessInfo.nameFa || "سانیهوم"}
|
alt={businessInfo.nameFa || "سانیهوم"}
|
||||||
className="h-9 w-auto object-contain"
|
className="h-[72px] w-auto object-contain"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="font-display text-lg font-bold tracking-tight">
|
<span className="font-display text-lg font-bold tracking-tight">
|
||||||
@@ -46,16 +46,16 @@ export function Footer({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{businessInfo?.about && (
|
{businessInfo?.about && (
|
||||||
<p className="text-sm leading-relaxed text-white/70">{businessInfo.about}</p>
|
<p className="text-sm leading-relaxed text-black/70">{businessInfo.about}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="mb-3 text-sm font-bold">دسترسی سریع</h4>
|
<h4 className="mb-3 text-sm font-bold">دسترسی سریع</h4>
|
||||||
<ul className="space-y-2 text-sm text-white/70">
|
<ul className="space-y-2 text-sm text-black/70">
|
||||||
{quickLinks.map((link) => (
|
{quickLinks.map((link) => (
|
||||||
<li key={link}>
|
<li key={link}>
|
||||||
<a href="#" className="transition-colors hover:text-white">
|
<a href="#" className="transition-colors hover:text-black">
|
||||||
{link}
|
{link}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -66,12 +66,12 @@ export function Footer({
|
|||||||
<div>
|
<div>
|
||||||
<h4 className="mb-3 text-sm font-bold">دستهبندیها</h4>
|
<h4 className="mb-3 text-sm font-bold">دستهبندیها</h4>
|
||||||
{categories.length === 0 ? (
|
{categories.length === 0 ? (
|
||||||
<p className="text-sm text-white/50">هنوز دستهبندیای ثبت نشده است.</p>
|
<p className="text-sm text-black/50">هنوز دستهبندیای ثبت نشده است.</p>
|
||||||
) : (
|
) : (
|
||||||
<ul className="space-y-2 text-sm text-white/70">
|
<ul className="space-y-2 text-sm text-black/70">
|
||||||
{categories.slice(0, 5).map((cat) => (
|
{categories.slice(0, 5).map((cat) => (
|
||||||
<li key={cat.id}>
|
<li key={cat.id}>
|
||||||
<a href="#" className="transition-colors hover:text-white">
|
<a href="#" className="transition-colors hover:text-black">
|
||||||
{cat.name}
|
{cat.name}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -83,7 +83,7 @@ export function Footer({
|
|||||||
<div>
|
<div>
|
||||||
<h4 className="mb-3 text-sm font-bold">تماس با ما</h4>
|
<h4 className="mb-3 text-sm font-bold">تماس با ما</h4>
|
||||||
{hasContactInfo ? (
|
{hasContactInfo ? (
|
||||||
<ul className="space-y-2 text-sm text-white/70">
|
<ul className="space-y-2 text-sm text-black/70">
|
||||||
{businessInfo?.addresses.map((address) => <li key={address}>{address}</li>)}
|
{businessInfo?.addresses.map((address) => <li key={address}>{address}</li>)}
|
||||||
{businessInfo?.phoneNumbers.map((phone) => (
|
{businessInfo?.phoneNumbers.map((phone) => (
|
||||||
<li key={phone}>تلفن: {phone}</li>
|
<li key={phone}>تلفن: {phone}</li>
|
||||||
@@ -91,7 +91,7 @@ export function Footer({
|
|||||||
{businessInfo?.emails.map((email) => <li key={email}>ایمیل: {email}</li>)}
|
{businessInfo?.emails.map((email) => <li key={email}>ایمیل: {email}</li>)}
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-white/50">هنوز اطلاعات تماس ثبت نشده است.</p>
|
<p className="text-sm text-black/50">هنوز اطلاعات تماس ثبت نشده است.</p>
|
||||||
)}
|
)}
|
||||||
{socialEntries.length > 0 && (
|
{socialEntries.length > 0 && (
|
||||||
<div className="mt-4 flex gap-3">
|
<div className="mt-4 flex gap-3">
|
||||||
@@ -101,7 +101,7 @@ export function Footer({
|
|||||||
href={url}
|
href={url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="font-display flex h-8 w-8 items-center justify-center rounded-full border border-white/20 text-[10px] font-bold transition-colors hover:border-white hover:bg-white/10"
|
className="font-display flex h-8 w-8 items-center justify-center rounded-full border border-black/20 text-[10px] font-bold transition-colors hover:border-black hover:bg-black/5"
|
||||||
>
|
>
|
||||||
{socialLabels[key] ?? key.slice(0, 2).toUpperCase()}
|
{socialLabels[key] ?? key.slice(0, 2).toUpperCase()}
|
||||||
</a>
|
</a>
|
||||||
@@ -111,20 +111,20 @@ export function Footer({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-10 flex flex-col items-center justify-between gap-3 border-t border-white/10 pt-6 text-xs text-white/50 md:flex-row">
|
<div className="mt-10 flex flex-col items-center justify-between gap-3 border-t border-black/10 pt-6 text-xs text-black/50 md:flex-row">
|
||||||
<p>© ۱۴۰۵ سانیهوم — تمامی حقوق محفوظ است.</p>
|
<p>© ۱۴۰۵ سانیهوم — تمامی حقوق محفوظ است.</p>
|
||||||
<a
|
<a
|
||||||
href="https://meshkee.com"
|
href="https://meshkee.com"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
className="group relative inline-flex items-center gap-2.5 px-2.5 py-1.5 text-[#9c9c9c] transition-colors duration-300 hover:text-[#e0e0e0]"
|
className="group relative inline-flex items-center gap-2.5 px-2.5 py-1.5 text-black/50 transition-colors duration-300 hover:text-black"
|
||||||
>
|
>
|
||||||
<span className="pointer-events-none absolute inset-0" aria-hidden="true">
|
<span className="pointer-events-none absolute inset-0" aria-hidden="true">
|
||||||
<span className="absolute top-0 left-0 h-full w-px origin-top scale-y-0 bg-[#777] transition-transform duration-[280ms] delay-[420ms] group-hover:scale-y-100 group-hover:delay-0" />
|
<span className="absolute top-0 left-0 h-full w-px origin-top scale-y-0 bg-black/40 transition-transform duration-[280ms] delay-[420ms] group-hover:scale-y-100 group-hover:delay-0" />
|
||||||
<span className="absolute bottom-0 left-0 h-px w-full origin-left scale-x-0 bg-[#777] transition-transform duration-[280ms] delay-[280ms] group-hover:scale-x-100 group-hover:delay-[140ms]" />
|
<span className="absolute bottom-0 left-0 h-px w-full origin-left scale-x-0 bg-black/40 transition-transform duration-[280ms] delay-[280ms] group-hover:scale-x-100 group-hover:delay-[140ms]" />
|
||||||
<span className="absolute top-0 right-0 h-full w-px origin-bottom scale-y-0 bg-[#777] transition-transform duration-[280ms] delay-[140ms] group-hover:scale-y-100 group-hover:delay-[280ms]" />
|
<span className="absolute top-0 right-0 h-full w-px origin-bottom scale-y-0 bg-black/40 transition-transform duration-[280ms] delay-[140ms] group-hover:scale-y-100 group-hover:delay-[280ms]" />
|
||||||
<span className="absolute top-0 left-0 h-px w-full origin-right scale-x-0 bg-[#777] transition-transform duration-[280ms] delay-0 group-hover:scale-x-100 group-hover:delay-[420ms]" />
|
<span className="absolute top-0 left-0 h-px w-full origin-right scale-x-0 bg-black/40 transition-transform duration-[280ms] delay-0 group-hover:scale-x-100 group-hover:delay-[420ms]" />
|
||||||
</span>
|
</span>
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<img
|
<img
|
||||||
@@ -132,11 +132,11 @@ export function Footer({
|
|||||||
alt="Meshkee"
|
alt="Meshkee"
|
||||||
width={42}
|
width={42}
|
||||||
height={42}
|
height={42}
|
||||||
className="relative block h-[42px] w-auto shrink-0 object-contain opacity-70 transition-opacity duration-300 group-hover:opacity-100"
|
className="relative block h-[42px] w-auto shrink-0 object-contain opacity-60 brightness-0 transition-opacity duration-300 group-hover:opacity-100"
|
||||||
/>
|
/>
|
||||||
<span className="relative flex min-h-[42px] flex-col justify-center leading-[1.25]">
|
<span className="relative flex min-h-[42px] flex-col justify-center leading-[1.25]">
|
||||||
<span className="text-[11px]">Designed And Developed By</span>
|
<span className="text-[11px]">Designed And Developed By</span>
|
||||||
<span className="text-[13px] font-semibold text-[#cfcfcf] transition-colors duration-300 group-hover:text-white">
|
<span className="text-[13px] font-semibold text-black/70 transition-colors duration-300 group-hover:text-black">
|
||||||
Meshkee E-Commerce Team
|
Meshkee E-Commerce Team
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { createPortal } from "react-dom";
|
|||||||
import type { Category, CategoryNode, CategoryTreeGroup } from "@/lib/meshkee";
|
import type { Category, CategoryNode, CategoryTreeGroup } from "@/lib/meshkee";
|
||||||
import { EmptyState } from "@/components/ui/EmptyState";
|
import { EmptyState } from "@/components/ui/EmptyState";
|
||||||
import { CartButton } from "@/components/cart/CartButton";
|
import { CartButton } from "@/components/cart/CartButton";
|
||||||
|
import { ChevronLeftIcon, CloseIcon, MenuIcon, UserIcon } from "@/components/ui/icons";
|
||||||
import { SearchBar } from "./SearchBar";
|
import { SearchBar } from "./SearchBar";
|
||||||
|
|
||||||
const navLinks = [
|
const navLinks = [
|
||||||
@@ -27,7 +28,7 @@ function Logo({ src, large = false }: { src?: string | null; large?: boolean })
|
|||||||
className={
|
className={
|
||||||
large
|
large
|
||||||
? "h-[42px] w-auto object-contain md:h-[46px]"
|
? "h-[42px] w-auto object-contain md:h-[46px]"
|
||||||
: "h-20 w-auto object-contain md:h-24"
|
: "h-[70px] w-auto object-contain md:h-[86px]"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
@@ -107,9 +108,9 @@ function MobileDrawer({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
aria-label="بستن منو"
|
aria-label="بستن منو"
|
||||||
className="flex h-9 w-9 items-center justify-center rounded-lg text-xl text-muted transition-colors hover:bg-red-light hover:text-red"
|
className="flex h-9 w-9 items-center justify-center rounded-lg text-muted transition-colors hover:bg-red-light hover:text-red"
|
||||||
>
|
>
|
||||||
✕
|
<CloseIcon className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -188,7 +189,7 @@ function MobileDrawer({
|
|||||||
href={LOGIN_URL}
|
href={LOGIN_URL}
|
||||||
className="flex items-center gap-2 px-5 py-4 text-right font-medium transition-colors hover:bg-red-light/40 hover:text-red"
|
className="flex items-center gap-2 px-5 py-4 text-right font-medium transition-colors hover:bg-red-light/40 hover:text-red"
|
||||||
>
|
>
|
||||||
<span aria-hidden>👤</span>
|
<UserIcon className="h-4 w-4" />
|
||||||
ورود
|
ورود
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -231,9 +232,9 @@ export function Header({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => setDrawerOpen(true)}
|
onClick={() => setDrawerOpen(true)}
|
||||||
aria-label="منو"
|
aria-label="منو"
|
||||||
className="flex h-10 w-10 items-center justify-center rounded-lg border border-border text-xl transition-colors hover:border-red hover:text-red min-[1200px]:hidden"
|
className="flex h-10 w-10 items-center justify-center rounded-lg border border-border transition-colors hover:border-red hover:text-red min-[1200px]:hidden"
|
||||||
>
|
>
|
||||||
<span aria-hidden>☰</span>
|
<MenuIcon className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
<div className="hidden min-[1200px]:block">
|
<div className="hidden min-[1200px]:block">
|
||||||
<Logo src={logoUrl} />
|
<Logo src={logoUrl} />
|
||||||
@@ -250,16 +251,29 @@ export function Header({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-end gap-3 text-sm">
|
<div className="flex items-center justify-end gap-3 text-sm">
|
||||||
|
<div className="hidden items-center gap-2 rounded-2xl bg-surface p-1.5 sm:flex">
|
||||||
|
<CartButton />
|
||||||
|
<span className="h-8 w-px bg-border" aria-hidden />
|
||||||
<a
|
<a
|
||||||
href={LOGIN_URL}
|
href={LOGIN_URL}
|
||||||
className="hidden items-center gap-1.5 text-muted transition-colors hover:text-red sm:flex"
|
className="flex items-center gap-2 rounded-xl py-1 pr-1 transition-opacity hover:opacity-80"
|
||||||
>
|
>
|
||||||
<span>👤</span>
|
<span className="flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-red text-white">
|
||||||
<span>ورود</span>
|
<UserIcon className="h-5 w-5" />
|
||||||
|
</span>
|
||||||
|
<span className="text-right leading-tight">
|
||||||
|
<span className="block text-sm font-bold whitespace-nowrap text-foreground">
|
||||||
|
حساب کاربری
|
||||||
|
</span>
|
||||||
|
<span className="block text-xs whitespace-nowrap text-muted">ورود/ثبتنام</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="sm:hidden">
|
||||||
<CartButton />
|
<CartButton />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="border-t border-border py-3 min-[1200px]:hidden">
|
<div className="border-t border-border py-3 min-[1200px]:hidden">
|
||||||
<SearchBar />
|
<SearchBar />
|
||||||
@@ -279,7 +293,7 @@ export function Header({
|
|||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
className="flex shrink-0 items-center gap-2 rounded-lg bg-red px-4 py-2 font-medium text-white transition-colors hover:bg-red-dark"
|
className="flex shrink-0 items-center gap-2 rounded-lg bg-red px-4 py-2 font-medium text-white transition-colors hover:bg-red-dark"
|
||||||
>
|
>
|
||||||
<span aria-hidden>☰</span>
|
<MenuIcon className="h-4 w-4" />
|
||||||
دستهبندیها
|
دستهبندیها
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -294,9 +308,10 @@ export function Header({
|
|||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
href="/products"
|
href="/products"
|
||||||
className="text-xs font-medium text-red hover:text-red-dark"
|
className="flex items-center gap-1 text-xs font-medium text-red hover:text-red-dark"
|
||||||
>
|
>
|
||||||
مشاهده همه ←
|
مشاهده همه
|
||||||
|
<ChevronLeftIcon className="h-3.5 w-3.5" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ChevronLeftIcon } from "@/components/ui/icons";
|
||||||
|
|
||||||
type SectionTitleProps = {
|
type SectionTitleProps = {
|
||||||
title: string;
|
title: string;
|
||||||
enTitle?: string;
|
enTitle?: string;
|
||||||
@@ -29,9 +31,10 @@ export function SectionTitle({ title, enTitle, subtitle, action, actionHref }: S
|
|||||||
{action && actionHref && (
|
{action && actionHref && (
|
||||||
<a
|
<a
|
||||||
href={actionHref}
|
href={actionHref}
|
||||||
className="shrink-0 rounded-lg bg-red px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-red-dark"
|
className="flex shrink-0 items-center gap-1.5 rounded-lg bg-red px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-red-dark"
|
||||||
>
|
>
|
||||||
{action} ←
|
{action}
|
||||||
|
<ChevronLeftIcon className="h-4 w-4" />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
type IconProps = { className?: string };
|
||||||
|
|
||||||
|
// Shared light/outline icon set — thin stroke (1.75), rounded caps/joins,
|
||||||
|
// 24x24 viewBox, matching the chevrons already used in Carousel/ProductGallery.
|
||||||
|
// Prefer these over emoji anywhere in the UI.
|
||||||
|
|
||||||
|
export function MenuIcon({ className }: IconProps) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" className={className} aria-hidden>
|
||||||
|
<path
|
||||||
|
d="M4 7h16M4 12h16M4 17h16"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.75"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserIcon({ className }: IconProps) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" className={className} aria-hidden>
|
||||||
|
<circle cx="12" cy="8" r="3.25" stroke="currentColor" strokeWidth="1.75" />
|
||||||
|
<path
|
||||||
|
d="M4.75 19.25c0-3.45 3.24-6.25 7.25-6.25s7.25 2.8 7.25 6.25"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.75"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CartIcon({ className }: IconProps) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" className={className} aria-hidden>
|
||||||
|
<path
|
||||||
|
d="M3.5 4.5h1.6l1.1 2M6.2 6.5l1.65 7.3a1.5 1.5 0 0 0 1.46 1.17h6.9a1.5 1.5 0 0 0 1.46-1.15l1.23-5.32H6.2Z"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.75"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<circle cx="10" cy="19.5" r="1.15" stroke="currentColor" strokeWidth="1.6" />
|
||||||
|
<circle cx="16.5" cy="19.5" r="1.15" stroke="currentColor" strokeWidth="1.6" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CloseIcon({ className }: IconProps) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" className={className} aria-hidden>
|
||||||
|
<path
|
||||||
|
d="M6 6l12 12M18 6 6 18"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.75"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChevronLeftIcon({ className }: IconProps) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" className={className} aria-hidden>
|
||||||
|
<path
|
||||||
|
d="M14.5 6.5 9 12l5.5 5.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user