Redesign category showcase and convert products section to carousel

- Replace icon-based category tiles with curated photo cards (brown
  bottom overlay, single-row layout, taller aspect ratio, tighter gaps,
  no card frame, light brown section background) via new
  CategoryShowcase component and categoryIcons fallback images.
- Add ScrollReveal component for page-enter animations, used across
  the category showcase and other sections.
- Turn the homepage "New Products" grid into a horizontal snap-scroll
  carousel with prev/next controls (ProductsCarousel).
- Extend Pagination and the products page to preserve categoryId
  filters, and widen aspectRatioToCss to accept undefined.
- Document the static-image-slots system and API client conventions
  in CLAUDE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-30 09:10:31 +03:30
co-authored by Claude Sonnet 5
parent d486b2dd65
commit 26b8b64bf3
21 changed files with 752 additions and 186 deletions
+51
View File
@@ -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.