- Enlarge category carousel thumbnails (90px -> 104-140px responsive) and
confirm the slider/categories/banner static-image slots are all reading
correctly from the CMS (verified live, not a wiring bug)
- Fix installments page dropping "هندزفری و هدفون": it's a level-3 category,
not level-2, so level2.find() silently missed it - use findNode() over the
whole tree instead
- Extend gen-category-placeholders.mjs to generate a placeholder for every
category at every level (was level-2 only), needed for the fix above
- Add /about, /contact, /installments pages
- About: real copy transcribed from the live moalem.shop theme, real
product photos from the API, text-only brand strip (no scraped logos)
- Contact: ContactForm.tsx posts to the real POST /contact-submissions,
branch cards with key-less Google Maps embeds
- Installments: flat brand-colored hero (no photo/gradient), category
highlights reusing the same categories slot images as the homepage
- Replace the placeholder header/footer phone number with the real one, add
real branch addresses and Instagram/Telegram links (src/data/site.ts),
pulled from the live theme's footer
- Wire logo/favicon to GET /website/favicon (getFavicon() in api.ts) instead
of the static bundled files, so a dashboard upload now shows automatically;
layout.tsx metadata is now generateMetadata() to support this. The tenant's
uploaded logo/favicon currently belongs to a different business - the
wiring is correct and will self-correct once that's fixed in the dashboard
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
41 lines
2.1 KiB
JavaScript
41 lines
2.1 KiB
JavaScript
// Writes one placeholder thumbnail per product category (every level, not
|
|
// just level-2) into public/images/categories/{id}.svg. They are meant to be
|
|
// replaced with real artwork one file at a time — the carousel and any other
|
|
// page that links a specific category id (e.g. /installments) read the same
|
|
// paths either way, so every id needs a file, not just the level-2 ones the
|
|
// homepage carousel shows by default.
|
|
// Run: node scripts/gen-category-placeholders.mjs
|
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
|
|
const DOMAIN = process.env.NEXT_PUBLIC_SITE_DOMAIN || "moalem.shop";
|
|
const OUT = new URL("../public/images/categories/", import.meta.url);
|
|
|
|
const res = await fetch(
|
|
`https://api.meshkee.com/api/v1/tenants/${DOMAIN}/categories?entityType=product`
|
|
);
|
|
const { items } = await res.json();
|
|
|
|
// Root categories (parentId === null) have no icon of their own on this
|
|
// site — nothing links directly to "کالای دیجیتال" itself — so only their
|
|
// descendants get a placeholder.
|
|
const roots = new Set(items.filter((c) => c.parentId === null).map((c) => c.id));
|
|
const withIcons = items.filter((c) => !roots.has(c.id));
|
|
|
|
await mkdir(OUT, { recursive: true });
|
|
|
|
const escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
|
|
for (const cat of withIcons) {
|
|
const label = escape(cat.nameFa || cat.name);
|
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="120" height="120" role="img" aria-label="${label}">
|
|
<circle cx="60" cy="60" r="59" fill="#f6f7f9" stroke="#ececec"/>
|
|
<rect x="34" y="34" width="52" height="52" rx="12" fill="#fff" stroke="#e51e22" stroke-opacity="0.35" stroke-dasharray="5 4"/>
|
|
<text x="60" y="64" text-anchor="middle" font-family="Tahoma, sans-serif" font-size="11" fill="#7c7c7c">${label.slice(0, 9)}</text>
|
|
<text x="60" y="78" text-anchor="middle" font-family="Tahoma, sans-serif" font-size="8" fill="#c9c9c9">${cat.id}</text>
|
|
</svg>
|
|
`;
|
|
await writeFile(new URL(`${cat.id}.svg`, OUT), svg, "utf8");
|
|
}
|
|
|
|
console.log(`wrote ${withIcons.length} placeholders to public/images/categories/`);
|