From 7089078b4c7811f69a9dc059fec05d76747ae9ff Mon Sep 17 00:00:00 2001 From: "amirhosein.ashourloo" Date: Sun, 20 Sep 2026 00:13:53 +0330 Subject: [PATCH] Use bundled logo from public/ instead of the API Header, footer and og:image now read public/images/logo.png via LOGO_SRC in config.ts. The API's /website/favicon returned another business's mark, so getFavicon()/BrandAssets are removed and the tab icon is the bundled favicon.png. Footer logo is now 70px like the header (108px was sized for the old square mark; the new 200x48 wordmark would be 450px wide). Co-Authored-By: Claude Sonnet 5 --- AGENTS.md | 27 ++++++++++----------------- public/images/logo.png | Bin 3528 -> 7491 bytes src/app/layout.tsx | 33 ++++++++++----------------------- src/components/Footer.tsx | 19 ++++++------------- src/components/Header.tsx | 11 ++++------- src/lib/api.ts | 8 -------- src/lib/config.ts | 6 ++++++ src/lib/types.ts | 10 ---------- 8 files changed, 36 insertions(+), 78 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 31ffe03..1822352 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,7 +31,7 @@ fallbacks should update it. | `/website/sliders`, `/website/category-groups` | **empty** | | `/website/static-images` | **filled** — `slider` (2), `categories` (8 of 15), `one/two/three-banner-bg` all have real images. Verified live and rendering correctly; if a future check finds otherwise, suspect a stale build/deploy before suspecting the wiring. | | `/blogs` | **empty** (module enabled) | -| `/website/business-info` | phones/addresses/socialMedia still empty; `logoUrl`/`faviconUrl` are now set but point to a **different business's** mark (see "Brand") | +| `/website/business-info` | phones/addresses/socialMedia still empty; `logoUrl`/`faviconUrl` point to a **different business's** mark and are deliberately unused (see "Brand") | | `/products/by-id/{id}/technical-info` | `{ form: null, values: [] }` — empty on every product checked so far | | `/comments` | **empty**, but `POST` works (no bearer required by the API itself) | @@ -42,7 +42,6 @@ fallbacks should update it. | No prices | `src/lib/demoPricing.ts`, gated by `NEXT_PUBLIC_DEMO_PRICING=1` — deterministic price per product id | store-items exist | | No blog posts | `src/data/fallbackBlogs.ts` — the real posts from moalem.shop/articles, shown on the homepage and `/blog` as square-thumbnail cards that link to a real local `/blog/{id}/{slug}` page (`getFallbackBlogById()`); that page shows title/category/image plus a "coming soon" note since only those three fields are real, no scraped body content | `/blogs` returns items | | No category art past slot position 8 | placeholder SVGs in `public/images/categories/{id}.svg`, generated by `scripts/gen-category-placeholders.mjs` for every category at every level, not just level-2 | the `categories` slot has an image for that position | -| Wrong logo/favicon in API | `getFavicon()` is wired live (see "Brand") but the uploaded asset itself is wrong; no code fallback needed once the dashboard upload is fixed | the correct asset is uploaded | ## Brand @@ -50,21 +49,15 @@ Colors taken from the live moalem.shop theme, not invented: primary `#E51E22`, dark `#B10123`, ink `#2E2E2E`, body `#7C7C7C`. Fonts: IRANYekan (fa, local `public/fonts`) + Montserrat (latin, next/font). -- Logo/favicon: `getFavicon()` in `src/lib/api.ts` reads - `GET /tenants/moalem.shop/website/favicon` — the documented single source — - and `Header.tsx`/`Footer.tsx`/`generateMetadata()` in `layout.tsx` all use - it, falling back to the bundled `/images/logo.png` / `/favicon.png` only - when the API field is null. **As of 2026-09-06 the dashboard has a logo/ - favicon uploaded, but it's the wrong business's** (a home-appliances store's - 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 (desktop) logo renders at `h-[70px]`; footer logo stays at - `h-[108px]` (3x the original `h-9`/36px, on request) — the two were sized - independently, on request, so don't assume they should match. If the wrong - logo above still looks small at either 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. +- Logo: **bundled, not from the API** — `public/images/logo.png` (200x48 + wordmark, supplied by the business), referenced via `LOGO_SRC`/`LOGO_WIDTH`/ + `LOGO_HEIGHT` in `src/lib/config.ts` by `Header.tsx`, `Footer.tsx` and the + og:image in `layout.tsx`. This was an explicit decision (2026-09-20): the + API's `/website/favicon` returned another business's mark, so + `getFavicon()` was removed entirely — don't re-add it. Tab icon is the + bundled `public/favicon.png`. To change the logo, replace the file (keep + the same name; update `LOGO_WIDTH`/`LOGO_HEIGHT` if its shape changes). +- Header (desktop) and footer logos both render at `h-[70px] w-auto`. - 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`/ diff --git a/public/images/logo.png b/public/images/logo.png index 608fca3cdbead257347e29784ba583593f0638f1..b135bb9f50757156af6603211ae0cd064e00758d 100644 GIT binary patch delta 6645 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 fgNZQ{4Eh3X0-|}Gu1AW62m-mecsSQHgEIaE { - const brand = await safe(getFavicon(), NO_BRAND_ASSETS); - +// Tab icon and og:image use the bundled brand files in /public — on purpose +// not GET /website/favicon (that endpoint served another business's mark). +export function generateMetadata(): Metadata { return { metadataBase: new URL(SITE_URL), title: { @@ -41,7 +35,7 @@ export async function generateMetadata(): Promise { template: `%s | ${SITE_NAME}`, }, description: BASE_DESCRIPTION, - icons: [{ url: brand.faviconUrl || "/favicon.png", type: "image/png" }], + icons: [{ url: "/favicon.png", type: "image/png" }], openGraph: { type: "website", locale: "fa_IR", @@ -49,24 +43,17 @@ export async function generateMetadata(): Promise { title: `${SITE_NAME} | خرید موبایل، لپ‌تاپ و لوازم جانبی`, description: BASE_DESCRIPTION, url: SITE_URL, - // The dashboard logo is a square mark; the bundled fallback is a wide - // wordmark — the two aren't the same shape, so their og:image sizes - // can't share one hardcoded pair. - images: brand.logoUrl - ? [{ url: brand.logoUrl, width: 512, height: 512, alt: SITE_NAME }] - : [{ url: "/images/logo.png", width: 130, height: 36, alt: SITE_NAME }], + images: [{ url: LOGO_SRC, width: LOGO_WIDTH, height: LOGO_HEIGHT, alt: SITE_NAME }], }, }; } export default async function RootLayout({ children }: LayoutProps<"/">) { - const [categories, user, brand] = await Promise.all([ + const [categories, user] = await Promise.all([ safe(getCategories().then(buildCategoryTree), []), getSession(), - safe(getFavicon(), NO_BRAND_ASSETS), ]); const menu = carouselCategories(categories); - const logoUrl = brand.logoUrl || "/images/logo.png"; return ( @@ -74,9 +61,9 @@ export default async function RootLayout({ children }: LayoutProps<"/">) { -
+
{children}
-