Make homepage carousels fully dynamic, drop brand carousels, dynamic logo/favicon

- Replace the two hardcoded homepage carousels (SpecialSaleCarousel
  pinned to store-specials group 0 only, TopSellingCarousel reading
  from an unrelated plain product query) with StoreSpecialCarousels:
  loops over every group GET /store-specials returns, using each
  group's own title. A new carousel created in the admin panel (e.g.
  the "بهترین‌ها از نگاه شما" one just added) shows up automatically,
  no code change needed.
- Remove the brand-groups integration and its "سامسونگ" carousel
  entirely (getBrandGroups, BrandGroupCarousels) — brand-name
  carousels aren't wanted on this site per explicit instruction.
- SectionTitle's enTitle is now optional, since dynamic store-specials
  groups only have one title string, not a Persian/English pair.
- Move featured categories above the hero-adjacent special carousels
  per the requested homepage order; drop the "دسته‌بندی‌های پرطرفدار"
  heading and its "همه دسته‌ها" button, per request.
- Wire the header/footer logo and the favicon to the real business
  data (logoUrl/logoDarkUrl/faviconUrl from GET business-info) instead
  of static files; removed src/app/favicon.ico, which was silently
  winning over the new dynamic <link rel="icon">.
- CONTEXT.md: document the dynamic-carousel contract and the
  logo/favicon wiring so neither regresses to hardcoded.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
amirhosein.ashourloo
2026-09-15 17:41:46 +03:30
co-authored by Claude Sonnet 5
parent 5152b16d61
commit bc6cafaffa
12 changed files with 118 additions and 194 deletions
+10 -5
View File
@@ -17,12 +17,12 @@ const navLinks = [
const LOGIN_URL = "https://customer.sanihome.ir";
function Logo({ large = false }: { large?: boolean }) {
function Logo({ src, large = false }: { src?: string | null; large?: boolean }) {
return (
<a href="/" className="flex shrink-0 items-center">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/images/logo.png"
src={src || "/images/logo.png"}
alt="سانی‌هوم"
className={
large
@@ -56,10 +56,12 @@ function MobileDrawer({
open,
onClose,
categoryTree,
logoUrl,
}: {
open: boolean;
onClose: () => void;
categoryTree: CategoryTreeGroup[];
logoUrl?: string | null;
}) {
const [categoriesOpen, setCategoriesOpen] = useState(false);
const [mounted, setMounted] = useState(false);
@@ -100,7 +102,7 @@ function MobileDrawer({
}`}
>
<div className="flex items-center justify-between border-b border-border p-5">
<Logo />
<Logo src={logoUrl} />
<button
type="button"
onClick={onClose}
@@ -199,9 +201,11 @@ function MobileDrawer({
export function Header({
categoryTree,
categories,
logoUrl,
}: {
categoryTree: CategoryTreeGroup[];
categories: Category[];
logoUrl?: string | null;
}) {
const [menuOpen, setMenuOpen] = useState(false);
const [drawerOpen, setDrawerOpen] = useState(false);
@@ -232,13 +236,13 @@ export function Header({
<span aria-hidden>☰</span>
</button>
<div className="hidden min-[1200px]:block">
<Logo />
<Logo src={logoUrl} />
</div>
</div>
<div className="flex items-center justify-center min-[1200px]:flex-1 min-[1200px]:px-6">
<div className="min-[1200px]:hidden">
<Logo large />
<Logo src={logoUrl} large />
</div>
<div className="hidden w-full min-[1200px]:block">
<SearchBar />
@@ -360,6 +364,7 @@ export function Header({
open={drawerOpen}
onClose={() => setDrawerOpen(false)}
categoryTree={categoryTree}
logoUrl={logoUrl}
/>
</header>
);