Show real titleFa captions, 3x logo size, fix category hover border
- CategoryCarousel: caption under each circle now comes from the slot image's own titleFa (as the business typed it) instead of the resolved category's API name - identity resolution via linkUrl slug is still used for the href, just not for the visible label - Replace the hover ring (box-shadow) with a real 1px border - the ring rendered oddly against Swiper's transformed slide track, looking like it "leaked" into the row above; a border participates in normal box layout and doesn't have that problem (border-box sizing means zero layout shift) - Header/footer logo: h-9 (36px) -> h-[108px], 3x on request; header row height bumped to fit. Note: the currently-uploaded (wrong-business) logo has a lot of baked-in padding, so it still reads small even at 3x - that's the asset, not the sizing - Re-verified the static-image-slot wiring end to end against the original spec (url->img, linkUrl->href, aspectRatio from API, placeholder on empty/fail) - all still holds Also add a Deployment section to AGENTS.md: this repo's whole point is CI/CD from origin/main, and local commits sitting unpushed (as 3 commits were, until now) look indistinguishable from unfixed bugs to whoever is testing the deployed site. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
2249a07dee
commit
0ffbd953b3
@@ -58,6 +58,10 @@ Fonts: IRANYekan (fa, local `public/fonts`) + Montserrat (latin, next/font).
|
||||
mark, not موبایل معلم) — the wiring is correct and will pick up the right
|
||||
asset automatically the moment it's replaced in the dashboard; don't
|
||||
"fix" this by hardcoding the local fallback again.
|
||||
- Header/footer logo renders at `h-[108px]` (3x the original `h-9`/36px, on
|
||||
request). If the wrong logo above still looks small at that size, it's
|
||||
because that specific PNG has a lot of baked-in transparent padding around
|
||||
the mark — `object-contain` can't fix that, only the replacement asset can.
|
||||
- Contact data (phone, mobile, branch addresses, Instagram/Telegram) in
|
||||
`src/data/site.ts` is real, pulled from the live theme's footer — `GET
|
||||
/website/business-info` still returns empty `phoneNumbers`/`addresses`/
|
||||
@@ -142,10 +146,21 @@ business's upload order lines up with this site's category sort order. It
|
||||
doesn't, and there's no contract that it ever would — live data showed a
|
||||
laptop photo (`linkUrl` correctly said `?category=laptop`) landing on
|
||||
"موبایل" and "لوازم برقی" appearing with no photo uploaded for it at all,
|
||||
purely because of where it fell in the array. `titleFa` isn't reliable
|
||||
either — the same laptop image was titled "تبلت" (stale/copy-pasted text),
|
||||
contradicting its own `linkUrl`. The `linkUrl` query param was the one field
|
||||
that matched the actual photo content every time it was checked.
|
||||
purely because of where it fell in the array. The visible caption under each
|
||||
circle is that image's own `titleFa`, taken as typed — even on the one
|
||||
sample where it disagreed with the photo (that same laptop image was titled
|
||||
"تبلت"), it's still the business's own editorial text for the tile, and the
|
||||
`href` (built from the `linkUrl` slug, resolved to this site's own canonical
|
||||
`/products/category/{id}/{slug}` rather than linking off-site to the literal
|
||||
`linkUrl`) is what actually has to be correct for navigation to work.
|
||||
|
||||
**Category circle hover:** use a real `border` (1px, transparent → `border-brand`
|
||||
on `group-hover`), not a `ring`/box-shadow. A ring rendered inside a Swiper
|
||||
slide painted like it was "leaking" into the row above — box-shadow doesn't
|
||||
participate in normal layout the way a border does, and interacts oddly with
|
||||
Swiper's transformed `.swiper-wrapper` track. `border` with this site's
|
||||
global `box-sizing: border-box` reset adds zero layout shift, so it's the
|
||||
safer default for any future hover-outline effect inside a carousel.
|
||||
|
||||
Homepage banner placement (mirrors the logilook.com reference given for this
|
||||
layout): hero → categories → hot deals → **three-banner-bg** → موبایل
|
||||
@@ -222,3 +237,14 @@ npm run dev # localhost:3000
|
||||
npm run build
|
||||
node scripts/gen-category-placeholders.mjs # refresh category thumb placeholders
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
`origin` is `gitea.meshkee.com/meshkee-websites/moalem-shop.git`, `main` branch.
|
||||
Whatever serves the business's preview/live URL deploys from `origin/main` —
|
||||
**committing locally is not enough**, push too. A whole session's worth of
|
||||
work (2026-09-06: about/contact/installments pages, the category-slot
|
||||
identity fix, live logo/favicon wiring) once sat 3 commits ahead of
|
||||
`origin/main` unpushed, and the business reported bugs that were already
|
||||
fixed locally — they were looking at the old deployed code. Check
|
||||
`git status` for "ahead of origin" before telling anyone a fix is live.
|
||||
|
||||
@@ -12,10 +12,11 @@ import type { CategoryNode, StaticImageSlot } from "@/lib/types";
|
||||
|
||||
// Fully slot-driven: each image in the "categories" slot carries its own
|
||||
// linkUrl (e.g. "...?category=mobile"), whose `category` param is the real
|
||||
// DB slug — that's what identifies which category a photo is for, not the
|
||||
// image's position in the list or its (business-typed, sometimes wrong)
|
||||
// titleFa. A category the business hasn't uploaded a photo for simply isn't
|
||||
// shown here — no placeholder, per the "only what's in the panel" brief.
|
||||
// DB slug — that's what identifies which category a photo is FOR (used to
|
||||
// build the real, in-site link target). The visible caption is the
|
||||
// business's own titleFa for that image, taken as typed — a category the
|
||||
// business hasn't uploaded a photo for simply isn't shown here, no
|
||||
// placeholder, per the "only what's in the panel" brief.
|
||||
// See AGENTS.md "Static-image slots" for the mismatch this replaced.
|
||||
export default function CategoryCarousel({
|
||||
roots,
|
||||
@@ -29,9 +30,10 @@ export default function CategoryCarousel({
|
||||
const catSlug = categorySlugFromLinkUrl(img.linkUrl);
|
||||
const cat = catSlug ? findNodeBySlug(roots, catSlug) : undefined;
|
||||
if (!cat) return null;
|
||||
return { key: img.id, art: img.url, cat };
|
||||
const label = img.titleFa || img.titleEn || cat.nameFa || cat.name;
|
||||
return { key: img.id, art: img.url, label, href: categoryHref(cat.id, cat.nameFa, cat.name) };
|
||||
})
|
||||
.filter((x): x is { key: string; art: string; cat: CategoryNode } => Boolean(x));
|
||||
.filter((x): x is { key: string; art: string; label: string; href: string } => Boolean(x));
|
||||
|
||||
if (items.length === 0) return null;
|
||||
|
||||
@@ -49,21 +51,29 @@ export default function CategoryCarousel({
|
||||
1024: { slidesPerView: 7 },
|
||||
}}
|
||||
>
|
||||
{items.map(({ key, art, cat }) => {
|
||||
const label = cat.nameFa || cat.name;
|
||||
return (
|
||||
<SwiperSlide key={key}>
|
||||
<Link href={categoryHref(cat.id, cat.nameFa, cat.name)} className="group flex flex-col items-center gap-2">
|
||||
<span className="relative size-[104px] overflow-hidden rounded-full bg-surface transition group-hover:bg-brand-soft sm:size-[124px] lg:size-[140px]">
|
||||
<Image src={art} alt={label} fill sizes="140px" className="object-contain p-3" />
|
||||
</span>
|
||||
<span className="text-center text-[13.5px] text-ink transition group-hover:text-brand">
|
||||
{label}
|
||||
</span>
|
||||
</Link>
|
||||
</SwiperSlide>
|
||||
);
|
||||
})}
|
||||
{items.map(({ key, art, label, href }) => (
|
||||
<SwiperSlide key={key}>
|
||||
<Link href={href} className="group flex flex-col items-center gap-2">
|
||||
{/* A real border, not ring/box-shadow — box-shadow rings can
|
||||
paint oddly against Swiper's transformed slide track
|
||||
(looked like the border "leaking" into the row above).
|
||||
border-box sizing (this site's global reset) means the
|
||||
1px border adds no layout shift. */}
|
||||
<span className="relative size-[104px] overflow-hidden rounded-full border border-transparent bg-surface transition-all duration-300 group-hover:border-brand group-hover:shadow-md sm:size-[124px] lg:size-[140px]">
|
||||
<Image
|
||||
src={art}
|
||||
alt={label}
|
||||
fill
|
||||
sizes="140px"
|
||||
className="rounded-full object-contain p-3 transition-transform duration-300 group-hover:scale-110"
|
||||
/>
|
||||
</span>
|
||||
<span className="text-center text-[13.5px] text-ink transition group-hover:text-brand">
|
||||
{label}
|
||||
</span>
|
||||
</Link>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -17,9 +17,15 @@ export default function Footer({
|
||||
<footer className="mt-14 border-t border-line bg-surface">
|
||||
<div className="boxed grid gap-8 py-10 md:grid-cols-4">
|
||||
<div className="md:col-span-2">
|
||||
{/* h-9 w-auto so a square dashboard logo and the wide fallback
|
||||
wordmark both render undistorted — see Header.tsx. */}
|
||||
<Image src={logoUrl} alt={SITE_NAME} width={140} height={40} className="h-9 w-auto object-contain" />
|
||||
{/* h-[108px] w-auto so a square dashboard logo and the wide
|
||||
fallback wordmark both render undistorted — see Header.tsx. */}
|
||||
<Image
|
||||
src={logoUrl}
|
||||
alt={SITE_NAME}
|
||||
width={280}
|
||||
height={108}
|
||||
className="h-[108px] w-auto object-contain"
|
||||
/>
|
||||
<p className="mt-3 max-w-md text-[13px] leading-7 text-body">{SITE_TAGLINE}</p>
|
||||
<a
|
||||
href={PHONE_HREF}
|
||||
|
||||
@@ -28,12 +28,21 @@ export default function Header({
|
||||
<header className="sticky top-0 z-40 w-full border-b border-line bg-white">
|
||||
<div className="boxed">
|
||||
{/* Mobile keeps the header down to the search box alone — account,
|
||||
cart and browsing live in the fixed bottom bar instead. */}
|
||||
<div className="flex h-[70px] items-center gap-4">
|
||||
cart and browsing live in the fixed bottom bar instead. The row
|
||||
is taller on lg so a prominent 108px logo (3x the old 36px) has
|
||||
room without cramming the search box/buttons beside it. */}
|
||||
<div className="flex h-[70px] items-center gap-4 lg:h-32">
|
||||
<Link href="/" className="hidden shrink-0 lg:block" aria-label={SITE_NAME}>
|
||||
{/* h-9 w-auto (not a fixed box) so a square dashboard logo mark
|
||||
and the wide fallback wordmark both render undistorted. */}
|
||||
<Image src={logoUrl} alt={SITE_NAME} width={140} height={40} className="h-9 w-auto object-contain" priority />
|
||||
{/* h-[108px] w-auto (not a fixed box) so a square dashboard logo
|
||||
mark and the wide fallback wordmark both render undistorted. */}
|
||||
<Image
|
||||
src={logoUrl}
|
||||
alt={SITE_NAME}
|
||||
width={280}
|
||||
height={108}
|
||||
className="h-[108px] w-auto object-contain"
|
||||
priority
|
||||
/>
|
||||
</Link>
|
||||
|
||||
<div className="flex-1">
|
||||
|
||||
Reference in New Issue
Block a user