diff --git a/.gitignore b/.gitignore
index 7be1c20..4590425 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,7 @@ next-env.d.ts
# claude code local settings
.claude/settings.local.json
+
+# raw source photos (unoptimized originals; only the derived files in
+# public/images/ are actually used by the site)
+/public/Image Sample/
diff --git a/CLAUDE.md b/CLAUDE.md
index 43c994c..970aa52 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1 +1,52 @@
@AGENTS.md
+
+# Arad Arisman — Meshkee backend integration
+
+This site is a Next.js storefront for **aradarisman.com**, backed by the
+Meshkee Website API (`https://api.meshkee.com/api/v1`, docs at
+`https://api.meshkee.com/docs/website`). All backend access goes through
+`src/lib/meshkee.ts` — do not call the API directly from components/pages.
+
+- Products (`getProducts`, `getProduct`) and blog posts (`getPosts`,
+ `getPost`) are fetched live, tenant-scoped to `TENANT_DOMAIN`
+ (`aradarisman.com`). Blog field names (`Post` type) are **inferred** from
+ the Product/Category naming convention since no tenant has published
+ posts to verify against yet — accessors fall back across plausible field
+ names (`postTitle`, `postContent`, etc.). Re-check against a real
+ published post once one exists and simplify the fallbacks if the guess
+ was wrong.
+- Category tiles are derived from live products (`getCategorySummary`), not
+ the raw `/categories` endpoint — that taxonomy has duplicate entries
+ sharing the same display name under different ids (backend data-entry
+ artifact). The summary merges by name and links to whichever id holds
+ the most products under that name.
+
+## Static image slots (business-managed overrides)
+
+`getStaticImageSlots` / `getStaticImageSlot(key)` read
+`/tenants/{domain}/website/static-images` — named slots the business owner
+can fill with their own images from the Meshkee dashboard. Current mapping:
+
+| Slot key | Kind | Component | Fallback when empty/unset |
+|-------------------|--------|--------------------|----------------------------------------|
+| `slider` | list | `HeroSlider` | 3 local photos in `hero-slider-*.jpg` with authored copy |
+| `categories` | list | `CategoryShowcase` | icon-based cards derived from live product categories |
+| `four-icon-image` | list(4)| `Features` | 4 local icons + authored copy, per-index override |
+| `about-us` | single | `About` | local `hero-2.jpg` |
+| `brands` | list | `Partners` | 6 local partner logos |
+
+**Rule: a slot with zero images (or a failed fetch) must never break the
+page — always fall back to the existing local/derived content.**
+`getStaticImageSlots` already swallows fetch errors and returns `[]`.
+
+Each `StaticImageItem` carries `url`, optional `titleFa`/`subtext`/
+`linkUrl`, and its own `width`/`height`. Respect `slot.aspectRatio`
+(`"21:9"` etc, via `aspectRatioToCss`) for slot-driven image containers
+instead of hardcoding a Tailwind aspect class — if you resize/recrop a
+*local* fallback image during development, update the corresponding
+component's fallback styling to match, since slot-driven and fallback
+images render through the same container and must not look broken when
+swapped.
+
+`aradarisman.com` currently has **zero** slots configured, so the site
+renders through the fallback path everywhere — this is expected, not a bug.
diff --git a/public/images/category-photo-concentrate.jpg b/public/images/category-photo-concentrate.jpg
new file mode 100644
index 0000000..d6b4e3f
Binary files /dev/null and b/public/images/category-photo-concentrate.jpg differ
diff --git a/public/images/category-photo-premix.jpg b/public/images/category-photo-premix.jpg
new file mode 100644
index 0000000..32f1ac8
Binary files /dev/null and b/public/images/category-photo-premix.jpg differ
diff --git a/public/images/category-photo-rice.jpg b/public/images/category-photo-rice.jpg
new file mode 100644
index 0000000..99217dd
Binary files /dev/null and b/public/images/category-photo-rice.jpg differ
diff --git a/public/images/category-photo-supplement.jpg b/public/images/category-photo-supplement.jpg
new file mode 100644
index 0000000..5e86d58
Binary files /dev/null and b/public/images/category-photo-supplement.jpg differ
diff --git a/public/images/category-photo-wheat.jpg b/public/images/category-photo-wheat.jpg
new file mode 100644
index 0000000..6d72f1a
Binary files /dev/null and b/public/images/category-photo-wheat.jpg differ
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 3f34fac..f06d519 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,17 +1,20 @@
import HeroSlider from "@/components/HeroSlider";
+import CategoryShowcase from "@/components/CategoryShowcase";
import Features from "@/components/Features";
-import Categories from "@/components/Categories";
import Stats from "@/components/Stats";
import Products from "@/components/Products";
import About from "@/components/About";
import Partners from "@/components/Partners";
+import { getStaticImageSlot } from "@/lib/meshkee";
+
+export default async function Home() {
+ const sliderSlot = await getStaticImageSlot("slider");
-export default function Home() {
return (
<>
-
+
+
-
diff --git a/src/app/products/page.tsx b/src/app/products/page.tsx
index b22d1ef..2d2b8c5 100644
--- a/src/app/products/page.tsx
+++ b/src/app/products/page.tsx
@@ -1,4 +1,5 @@
import type { Metadata } from "next";
+import Link from "next/link";
import Container from "@/components/Container";
import PageBanner from "@/components/PageBanner";
import ProductCard from "@/components/ProductCard";
@@ -16,18 +17,20 @@ const PAGE_SIZE = 6;
export default async function ProductsPage({
searchParams,
}: {
- searchParams: Promise<{ page?: string }>;
+ searchParams: Promise<{ page?: string; categoryId?: string }>;
}) {
- const { page } = await searchParams;
+ const { page, categoryId } = await searchParams;
const requestedPage = Math.max(1, Number(page) || 1);
const { items, total } = await getProducts({
page: requestedPage,
pageSize: PAGE_SIZE,
+ categoryId,
});
const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
const currentPage = Math.min(requestedPage, totalPages);
+ const activeCategoryName = categoryId ? items[0]?.categoryNameFa : null;
return (
<>
@@ -39,6 +42,23 @@ export default async function ProductsPage({
+ {categoryId && (
+
+
+ فیلتر شده بر اساس دستهبندی:{" "}
+
+ {activeCategoryName || "دستهبندی انتخابی"}
+
+
+
+ حذف فیلتر
+
+