@thorprovider/create-storefront 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/bin/install.js +116 -0
- package/commands/sf-add-view.md +21 -0
- package/commands/sf-init.md +16 -0
- package/commands/sf-theme.md +15 -0
- package/commands/sf-view.md +20 -0
- package/package.json +40 -0
- package/recipes/archetype.schema.json +39 -0
- package/recipes/archetypes.json +148 -0
- package/recipes/recipe.schema.json +59 -0
- package/recipes/recipes.json +90 -0
- package/recipes/sections.json +46 -0
- package/recipes/validate.mjs +190 -0
- package/skills/building-storefronts/SKILL.md +178 -0
- package/skills/building-storefronts/references/frontend-integration.md +229 -0
- package/skills/json-render-core/SKILL.md +291 -0
- package/skills/json-render-next/SKILL.md +194 -0
- package/skills/json-render-react/SKILL.md +298 -0
- package/skills/json-render-remotion/SKILL.md +111 -0
- package/skills/json-render-shadcn/SKILL.md +159 -0
- package/skills/json-render-solid/SKILL.md +204 -0
- package/skills/nextjs-shadcn/SKILL.md +303 -0
- package/skills/nextjs-shadcn/references/architecture.md +499 -0
- package/skills/nextjs-shadcn/references/project-setup.md +127 -0
- package/skills/nextjs-shadcn/references/shadcn-platform.md +258 -0
- package/skills/nextjs-shadcn/references/sidebar.md +274 -0
- package/skills/nextjs-shadcn/references/styling.md +555 -0
- package/skills/sf-scaffold/SKILL.md +118 -0
- package/skills/sf-theme-gen/SKILL.md +44 -0
- package/skills/sf-view-gen/SKILL.md +94 -0
- package/skills/shadcn-component-discovery/SKILL.md +273 -0
- package/skills/shadcn-component-discovery/references/registries.md +226 -0
- package/skills/shadcn-theming/SKILL.md +104 -0
- package/skills/shadcn-theming/references/templates/theme-setup.md +109 -0
- package/skills/shadcn-theming/references/theming-guide.md +90 -0
- package/skills/storefront-best-practices/SKILL.md +421 -0
- package/skills/storefront-best-practices/reference/components/breadcrumbs.md +123 -0
- package/skills/storefront-best-practices/reference/components/cart-popup.md +189 -0
- package/skills/storefront-best-practices/reference/components/country-selector.md +298 -0
- package/skills/storefront-best-practices/reference/components/footer.md +112 -0
- package/skills/storefront-best-practices/reference/components/hero.md +241 -0
- package/skills/storefront-best-practices/reference/components/megamenu.md +239 -0
- package/skills/storefront-best-practices/reference/components/navbar.md +397 -0
- package/skills/storefront-best-practices/reference/components/popups.md +221 -0
- package/skills/storefront-best-practices/reference/components/product-card.md +125 -0
- package/skills/storefront-best-practices/reference/components/product-reviews.md +217 -0
- package/skills/storefront-best-practices/reference/components/product-slider.md +174 -0
- package/skills/storefront-best-practices/reference/components/search.md +101 -0
- package/skills/storefront-best-practices/reference/connecting-to-backend.md +391 -0
- package/skills/storefront-best-practices/reference/design.md +388 -0
- package/skills/storefront-best-practices/reference/features/promotions.md +307 -0
- package/skills/storefront-best-practices/reference/features/wishlist.md +230 -0
- package/skills/storefront-best-practices/reference/layouts/account.md +380 -0
- package/skills/storefront-best-practices/reference/layouts/cart.md +316 -0
- package/skills/storefront-best-practices/reference/layouts/checkout.md +486 -0
- package/skills/storefront-best-practices/reference/layouts/home-page.md +264 -0
- package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +231 -0
- package/skills/storefront-best-practices/reference/layouts/product-details.md +527 -0
- package/skills/storefront-best-practices/reference/layouts/product-listing.md +520 -0
- package/skills/storefront-best-practices/reference/layouts/static-pages.md +356 -0
- package/skills/storefront-best-practices/reference/medusa.md +307 -0
- package/skills/storefront-best-practices/reference/mobile-responsiveness.md +183 -0
- package/skills/storefront-best-practices/reference/seo.md +195 -0
- package/templates/app/app/[[...slug]]/page.tsx +17 -0
- package/templates/app/app/[[...slug]]/renderer.tsx +10 -0
- package/templates/app/app/globals.css +101 -0
- package/templates/app/app/layout.tsx +35 -0
- package/templates/app/lib/__STOREFRONT__/catalog.ts +132 -0
- package/templates/app/lib/__STOREFRONT__/handlers.ts +33 -0
- package/templates/app/lib/__STOREFRONT__/registry.tsx +134 -0
- package/templates/app/lib/__STOREFRONT__/runtime.ts +25 -0
- package/templates/app/lib/__STOREFRONT__/spec/home.ts +62 -0
- package/templates/app/lib/__STOREFRONT__/spec/index.ts +59 -0
- package/templates/app/lib/__STOREFRONT__/spec/types.ts +14 -0
- package/templates/app/lib/__STOREFRONT__/state.ts +35 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
# Product Listing Page Layout
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Overview](#overview)
|
|
6
|
+
- [Reusable Component Architecture](#reusable-component-architecture-recommended)
|
|
7
|
+
- [Decision: Pagination vs Infinite Scroll vs Load More](#decision-pagination-vs-infinite-scroll-vs-load-more)
|
|
8
|
+
- [Decision: Filter Pattern Selection](#decision-filter-pattern-selection)
|
|
9
|
+
- [Product Grid Layout](#product-grid-layout)
|
|
10
|
+
- [Filtering Strategy](#filtering-strategy)
|
|
11
|
+
- [Sorting Strategy](#sorting-strategy)
|
|
12
|
+
- [Backend Integration](#backend-integration)
|
|
13
|
+
- [Empty and No Results States](#empty-and-no-results-states)
|
|
14
|
+
- [Performance Optimization](#performance-optimization)
|
|
15
|
+
- [Mobile Optimization](#mobile-optimization)
|
|
16
|
+
- [Checklist](#checklist)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
Primary browsing interface where users compare products, apply filters, and navigate to product details. Critical for product discovery and conversion.
|
|
21
|
+
|
|
22
|
+
### Key Requirements
|
|
23
|
+
|
|
24
|
+
- Responsive product grid (3-4 columns desktop, 2 mobile)
|
|
25
|
+
- Filtering (categories, price, attributes)
|
|
26
|
+
- Sorting options (price, popularity, newest)
|
|
27
|
+
- Pagination, infinite scroll, or load more
|
|
28
|
+
- Results count and active filter indicators
|
|
29
|
+
- Clear "no results" state with suggestions
|
|
30
|
+
- Fast loading and filtering (<1s filter updates)
|
|
31
|
+
- Backend integration for dynamic filtering
|
|
32
|
+
|
|
33
|
+
### Reusable Component Architecture (RECOMMENDED)
|
|
34
|
+
|
|
35
|
+
**Build product listing as a reusable component that works across multiple pages:**
|
|
36
|
+
|
|
37
|
+
✅ **Use the same product listing component for:**
|
|
38
|
+
- "Shop All" page (all products, no category filter)
|
|
39
|
+
- Category pages (filtered by specific category)
|
|
40
|
+
- Search results page (filtered by search query)
|
|
41
|
+
- Sale/Promotion pages (filtered by discount/promotion)
|
|
42
|
+
- Collection pages (curated product sets)
|
|
43
|
+
- Brand pages (filtered by brand)
|
|
44
|
+
|
|
45
|
+
**Benefits of reusable approach:**
|
|
46
|
+
- Single source of truth for product browsing UI
|
|
47
|
+
- Consistent filtering, sorting, and pagination behavior across entire site
|
|
48
|
+
- Easier maintenance (fix bugs once, applies everywhere)
|
|
49
|
+
- Better user experience (familiar interface on every product browsing page)
|
|
50
|
+
- Significantly less code duplication
|
|
51
|
+
|
|
52
|
+
**What to make configurable:**
|
|
53
|
+
- Initial filter parameters (category ID, search query, promotion ID, brand, etc.)
|
|
54
|
+
- Page title and breadcrumbs
|
|
55
|
+
- Whether to show filters sidebar (some pages may hide certain filters)
|
|
56
|
+
- Default sort order (category: featured, search: relevance, sale: discount %)
|
|
57
|
+
- Number of products per page
|
|
58
|
+
- Filter options available (hide category filter on category pages, etc.)
|
|
59
|
+
|
|
60
|
+
**Common mistake:**
|
|
61
|
+
- ❌ Creating separate components/pages for "Shop All", category pages, and search results with duplicated filtering/sorting/pagination logic
|
|
62
|
+
- ✅ Build one reusable ProductListing component that accepts filter parameters and reuse it across all product browsing pages
|
|
63
|
+
|
|
64
|
+
### Routing Pattern
|
|
65
|
+
|
|
66
|
+
**CRITICAL: Always use dynamic routes for category pages, NEVER static pages.**
|
|
67
|
+
|
|
68
|
+
Category/listing pages must use dynamic routes that accept a parameter (handle, slug, or category ID):
|
|
69
|
+
|
|
70
|
+
**Correct examples:**
|
|
71
|
+
- Next.js App Router: `app/categories/[handle]/page.tsx`
|
|
72
|
+
- Next.js Pages Router: `pages/categories/[handle].tsx`
|
|
73
|
+
- SvelteKit: `routes/categories/[handle]/+page.svelte`
|
|
74
|
+
- TanStack Start: `routes/categories/$handle.tsx`
|
|
75
|
+
- Remix: `routes/categories.$handle.tsx`
|
|
76
|
+
|
|
77
|
+
**Wrong examples:**
|
|
78
|
+
- ❌ `pages/categories/women.tsx` (static file per category)
|
|
79
|
+
- ❌ `pages/categories/men.tsx` (doesn't scale)
|
|
80
|
+
|
|
81
|
+
Fetch category products in the dynamic route based on the handle/ID parameter from the URL.
|
|
82
|
+
|
|
83
|
+
## Decision: Pagination vs Infinite Scroll vs Load More
|
|
84
|
+
|
|
85
|
+
This is a critical ecommerce decision that affects user experience, SEO, and technical implementation.
|
|
86
|
+
|
|
87
|
+
### Use Pagination When:
|
|
88
|
+
|
|
89
|
+
**User needs:**
|
|
90
|
+
- Return to specific result pages
|
|
91
|
+
- Precise control over browsing
|
|
92
|
+
- Professional/research shopping (compare systematically)
|
|
93
|
+
- B2B shoppers (procurement, large orders)
|
|
94
|
+
|
|
95
|
+
**Product characteristics:**
|
|
96
|
+
- Position matters (rankings, bestsellers)
|
|
97
|
+
- Large catalog with stable ordering
|
|
98
|
+
- Products require careful comparison
|
|
99
|
+
|
|
100
|
+
**Technical benefits:**
|
|
101
|
+
- SEO-friendly (unique URL per page)
|
|
102
|
+
- Better for indexing and crawling
|
|
103
|
+
- Easier back button support
|
|
104
|
+
- Lower memory usage
|
|
105
|
+
|
|
106
|
+
**Implementation:**
|
|
107
|
+
```typescript
|
|
108
|
+
// URL structure: /products?page=2&category=shirts
|
|
109
|
+
// Each page has unique URL for SEO
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Best for:**
|
|
113
|
+
- Desktop-heavy audience
|
|
114
|
+
- B2B ecommerce
|
|
115
|
+
- Product comparison shopping
|
|
116
|
+
- Catalog with 100+ products
|
|
117
|
+
|
|
118
|
+
### Use Infinite Scroll When:
|
|
119
|
+
|
|
120
|
+
**User needs:**
|
|
121
|
+
- Exploratory browsing behavior
|
|
122
|
+
- Mobile-first experience
|
|
123
|
+
- Seamless discovery flow
|
|
124
|
+
- Fashion/visual shopping
|
|
125
|
+
|
|
126
|
+
**Product characteristics:**
|
|
127
|
+
- Visual-heavy products (fashion, art, photography)
|
|
128
|
+
- Impulse purchases
|
|
129
|
+
- Discovery-focused (Pinterest-style)
|
|
130
|
+
|
|
131
|
+
**Technical considerations:**
|
|
132
|
+
- More complex to implement
|
|
133
|
+
- Requires careful SEO handling (pagination URLs still needed)
|
|
134
|
+
- Higher memory usage (all loaded products stay in DOM)
|
|
135
|
+
- Need to handle browser back button carefully
|
|
136
|
+
|
|
137
|
+
**Implementation:**
|
|
138
|
+
```typescript
|
|
139
|
+
// Load more when user scrolls to bottom
|
|
140
|
+
// Keep pagination in URL for SEO: /products?page=2
|
|
141
|
+
// Use Intersection Observer API for detection
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Best for:**
|
|
145
|
+
- Mobile-first stores (>60% mobile traffic)
|
|
146
|
+
- Fashion, home decor, visual products
|
|
147
|
+
- Younger demographic (18-34)
|
|
148
|
+
- Discovery-focused shopping
|
|
149
|
+
|
|
150
|
+
### Use "Load More" Button When:
|
|
151
|
+
|
|
152
|
+
**Benefits of compromise:**
|
|
153
|
+
- User controls when to load (not automatic)
|
|
154
|
+
- Footer remains accessible (important for policies, contact)
|
|
155
|
+
- Better for slower connections (international users)
|
|
156
|
+
- Accessibility friendly (no automatic loading)
|
|
157
|
+
- Lower memory usage than infinite scroll
|
|
158
|
+
|
|
159
|
+
**Implementation:**
|
|
160
|
+
```typescript
|
|
161
|
+
// Button triggers next page load
|
|
162
|
+
// Append products to existing grid
|
|
163
|
+
// Show count: "Load 24 More Products"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Best for:**
|
|
167
|
+
- International audience (varying connection speeds)
|
|
168
|
+
- Footer content is important (legal, policies, contact)
|
|
169
|
+
- Accessibility concerns with infinite scroll
|
|
170
|
+
- Compromise between pagination and infinite scroll
|
|
171
|
+
|
|
172
|
+
### Hybrid Approach (Recommended):
|
|
173
|
+
|
|
174
|
+
Combine patterns based on context:
|
|
175
|
+
- Pagination for SEO (canonical URLs)
|
|
176
|
+
- Infinite scroll for UX (on user interaction)
|
|
177
|
+
- Load more for control (user-triggered)
|
|
178
|
+
|
|
179
|
+
**Example:**
|
|
180
|
+
```typescript
|
|
181
|
+
// Desktop: Pagination at bottom + infinite scroll option
|
|
182
|
+
// Mobile: Infinite scroll with pagination URLs for SEO
|
|
183
|
+
// All: Preserve scroll position on back button
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Decision: Filter Pattern Selection
|
|
187
|
+
|
|
188
|
+
### Sidebar Filters (Desktop)
|
|
189
|
+
|
|
190
|
+
**Use when:**
|
|
191
|
+
- Many filter options (5+ categories)
|
|
192
|
+
- Complex product attributes
|
|
193
|
+
- Power users (B2B, professional shoppers)
|
|
194
|
+
- Desktop-heavy traffic
|
|
195
|
+
|
|
196
|
+
**Layout:**
|
|
197
|
+
- Left sidebar (250-320px wide)
|
|
198
|
+
- Sticky position (scrolls with page)
|
|
199
|
+
- Collapsible sections (accordion)
|
|
200
|
+
- Apply immediately (no "Apply" button)
|
|
201
|
+
|
|
202
|
+
### Top Filters (Desktop)
|
|
203
|
+
|
|
204
|
+
**Use when:**
|
|
205
|
+
- Few filter options (2-4 key filters)
|
|
206
|
+
- Maximize grid space (full-width layout)
|
|
207
|
+
- Simple product categories
|
|
208
|
+
- Visual-first products (fashion)
|
|
209
|
+
|
|
210
|
+
**Layout:**
|
|
211
|
+
- Horizontal filter bar above grid
|
|
212
|
+
- Dropdowns or button toggles
|
|
213
|
+
- Limited options (price, category, brand)
|
|
214
|
+
- Compact design
|
|
215
|
+
|
|
216
|
+
### Drawer Filters (Mobile - Always)
|
|
217
|
+
|
|
218
|
+
**Pattern:**
|
|
219
|
+
- "Filters" button at top (shows active count badge)
|
|
220
|
+
- Slide-out drawer (full-screen or 80% width)
|
|
221
|
+
- Accordion sections
|
|
222
|
+
- "Apply" button at bottom (batch filtering)
|
|
223
|
+
- "Clear All" option
|
|
224
|
+
|
|
225
|
+
**Why batch filtering on mobile:**
|
|
226
|
+
- Prevents multiple re-renders on slow connections
|
|
227
|
+
- User can adjust multiple filters before applying
|
|
228
|
+
- Better mobile UX (less disruptive)
|
|
229
|
+
|
|
230
|
+
## Product Grid Layout
|
|
231
|
+
|
|
232
|
+
**Responsive columns:**
|
|
233
|
+
- Large desktop (>1440px): 4 columns
|
|
234
|
+
- Desktop (1024-1440px): 3-4 columns
|
|
235
|
+
- Tablet (768-1024px): 3 columns
|
|
236
|
+
- Mobile (< 768px): 2 columns
|
|
237
|
+
|
|
238
|
+
**Adjust based on product type:**
|
|
239
|
+
- Fashion/lifestyle: 3-4 columns (more visible at once)
|
|
240
|
+
- Electronics/detailed: 2-3 columns (larger cards, more detail)
|
|
241
|
+
- Furniture/large items: 2-3 columns (showcase details)
|
|
242
|
+
|
|
243
|
+
**Product card essentials:**
|
|
244
|
+
- Product image (primary)
|
|
245
|
+
- Title (truncated to 2 lines)
|
|
246
|
+
- Price (Medusa: display as-is, don't divide by 100)
|
|
247
|
+
- Optional: Rating, badges, wishlist
|
|
248
|
+
- See product-card.md for detailed guidelines
|
|
249
|
+
|
|
250
|
+
**Grid spacing:**
|
|
251
|
+
- 16-24px gap (desktop)
|
|
252
|
+
- 12-16px gap (mobile)
|
|
253
|
+
- Equal height rows (optional, improves visual consistency)
|
|
254
|
+
|
|
255
|
+
## Filtering Strategy
|
|
256
|
+
|
|
257
|
+
### Filter Types by Purpose
|
|
258
|
+
|
|
259
|
+
**Category filters:**
|
|
260
|
+
- Multi-select checkboxes
|
|
261
|
+
- Hierarchical (parent-child categories)
|
|
262
|
+
- Show product count per category
|
|
263
|
+
- Example: "Shirts (24)" "T-Shirts (12)"
|
|
264
|
+
|
|
265
|
+
**Price range filter:**
|
|
266
|
+
- Range slider (drag min/max)
|
|
267
|
+
- Or: Predefined ranges ("$0-$50", "$50-$100")
|
|
268
|
+
- Update dynamically as products filtered
|
|
269
|
+
- Show min/max from current results
|
|
270
|
+
|
|
271
|
+
**Attribute filters (Size, Color, Brand):**
|
|
272
|
+
- Multi-select checkboxes
|
|
273
|
+
- Visual swatches for colors
|
|
274
|
+
- Show available options based on current filters
|
|
275
|
+
- Gray out unavailable combinations
|
|
276
|
+
|
|
277
|
+
**Availability filters:**
|
|
278
|
+
- "In Stock" checkbox
|
|
279
|
+
- "On Sale" checkbox
|
|
280
|
+
- "New Arrivals" checkbox
|
|
281
|
+
- Single purpose, clear value
|
|
282
|
+
|
|
283
|
+
### Filter Behavior
|
|
284
|
+
|
|
285
|
+
**Filter persistence:**
|
|
286
|
+
- Save in URL parameters (shareable, bookmarkable)
|
|
287
|
+
- Example: `/products?category=shirts&price=0-50&color=blue`
|
|
288
|
+
- Restore filters on page reload
|
|
289
|
+
- Clear all filters should reset URL
|
|
290
|
+
|
|
291
|
+
### Active Filters Display
|
|
292
|
+
|
|
293
|
+
**Show active filters:**
|
|
294
|
+
- Above product grid
|
|
295
|
+
- Pill/tag format: "Blue ✕" "Under $50 ✕"
|
|
296
|
+
- Click X to remove individual filter
|
|
297
|
+
- "Clear All" link to remove all filters
|
|
298
|
+
- Count: "3 filters active"
|
|
299
|
+
|
|
300
|
+
## Sorting Strategy
|
|
301
|
+
|
|
302
|
+
### Common Sort Options
|
|
303
|
+
|
|
304
|
+
**Essential options:**
|
|
305
|
+
- **Featured** (default): Store's recommended order (bestsellers, promoted)
|
|
306
|
+
- **Price: Low to High**: Budget-conscious shoppers
|
|
307
|
+
- **Price: High to Low**: Premium product seekers
|
|
308
|
+
- **Newest**: Fashion, tech, time-sensitive products
|
|
309
|
+
- **Best Selling**: Social proof, popular choices
|
|
310
|
+
- **Top Rated**: Quality-focused shoppers
|
|
311
|
+
|
|
312
|
+
**Advanced options:**
|
|
313
|
+
- Name: A-Z (alphabetical)
|
|
314
|
+
- Discount: Highest % off (sale hunters)
|
|
315
|
+
- Reviews: Most reviewed (validation seekers)
|
|
316
|
+
|
|
317
|
+
### Sort Implementation
|
|
318
|
+
|
|
319
|
+
**Display:**
|
|
320
|
+
- Dropdown above product grid (right-aligned)
|
|
321
|
+
- Label: "Sort by:" or just dropdown
|
|
322
|
+
- Update products immediately on selection
|
|
323
|
+
- Show current sort in URL: `/products?order=-created_at`
|
|
324
|
+
|
|
325
|
+
**Backend integration:**
|
|
326
|
+
- Pass sort parameter to API (check backend docs for parameter name)
|
|
327
|
+
- Common parameters: `order`, `sort`, `sort_by`
|
|
328
|
+
- Common values: `-created_at` (desc), `+price` (asc), `-price` (desc)
|
|
329
|
+
|
|
330
|
+
**Preserve filters:**
|
|
331
|
+
- Sorting doesn't clear filters
|
|
332
|
+
- Maintains all active filters
|
|
333
|
+
- Updates URL with sort parameter
|
|
334
|
+
|
|
335
|
+
## Backend Integration
|
|
336
|
+
|
|
337
|
+
### Fetching Products
|
|
338
|
+
|
|
339
|
+
**Query parameters to include:**
|
|
340
|
+
- Category/collection filter (if applicable)
|
|
341
|
+
- Pagination (limit, offset or cursor)
|
|
342
|
+
- Sort order
|
|
343
|
+
- Filter values (price, attributes, etc.)
|
|
344
|
+
- For Medusa: `region_id` (required for correct pricing)
|
|
345
|
+
|
|
346
|
+
Check backend API documentation for exact parameter names and formats.
|
|
347
|
+
|
|
348
|
+
### Available Filters
|
|
349
|
+
|
|
350
|
+
**Dynamic filter updates:**
|
|
351
|
+
- Show only relevant filters for current category
|
|
352
|
+
- Display product count per filter option
|
|
353
|
+
- Gray out options with 0 products
|
|
354
|
+
- Update available options when filters change
|
|
355
|
+
|
|
356
|
+
### URL State Management
|
|
357
|
+
|
|
358
|
+
**Filter URL structure pattern:**
|
|
359
|
+
`/products?category_id=123&order=-created_at&page=2&price=0-50`
|
|
360
|
+
|
|
361
|
+
**Benefits:**
|
|
362
|
+
- Shareable links
|
|
363
|
+
- Bookmarkable searches
|
|
364
|
+
- Browser back/forward works correctly
|
|
365
|
+
- SEO-friendly (crawlable filter combinations)
|
|
366
|
+
|
|
367
|
+
**Implementation approach:**
|
|
368
|
+
- Read filters from URL query parameters on page load
|
|
369
|
+
- Update URL when filters change using URLSearchParams and history.pushState
|
|
370
|
+
- Parse URL parameters to reconstruct filter state
|
|
371
|
+
|
|
372
|
+
## Empty and No Results States
|
|
373
|
+
|
|
374
|
+
### No Products in Category
|
|
375
|
+
|
|
376
|
+
**When category is empty:**
|
|
377
|
+
- Message: "No products available yet"
|
|
378
|
+
- Subtext: "Check back soon for new arrivals"
|
|
379
|
+
- CTA: "Browse all products" or "Go to home"
|
|
380
|
+
- Alternative: Show related categories
|
|
381
|
+
- Optional: Newsletter signup for notifications
|
|
382
|
+
|
|
383
|
+
### No Results from Filters
|
|
384
|
+
|
|
385
|
+
**When filters too restrictive:**
|
|
386
|
+
- Message: "No products match your filters"
|
|
387
|
+
- Subtext: "Try removing some filters or adjusting your criteria"
|
|
388
|
+
- **Prominent "Clear All Filters" button**
|
|
389
|
+
- Show which filters might be too restrictive
|
|
390
|
+
- Suggestions: "Try expanding price range" or "Remove brand filter"
|
|
391
|
+
|
|
392
|
+
**Example:**
|
|
393
|
+
```
|
|
394
|
+
No products found
|
|
395
|
+
|
|
396
|
+
You filtered by:
|
|
397
|
+
- Color: Blue
|
|
398
|
+
- Size: XXL
|
|
399
|
+
- Price: $0-$20
|
|
400
|
+
|
|
401
|
+
Try:
|
|
402
|
+
• Removing size filter (only 2 XXL products)
|
|
403
|
+
• Expanding price range
|
|
404
|
+
• [Clear All Filters]
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### No Results from Search
|
|
408
|
+
|
|
409
|
+
**When search query returns nothing:**
|
|
410
|
+
- Message: "No results for '[query]'"
|
|
411
|
+
- Suggestions: Check spelling, try different keywords
|
|
412
|
+
- CTA: Browse popular categories
|
|
413
|
+
- Show search suggestions (similar queries)
|
|
414
|
+
- Display popular or trending products
|
|
415
|
+
|
|
416
|
+
## Performance Optimization
|
|
417
|
+
|
|
418
|
+
### Lazy Loading Images
|
|
419
|
+
|
|
420
|
+
**Implementation:**
|
|
421
|
+
- Load images as they come into viewport
|
|
422
|
+
- Use Intersection Observer API
|
|
423
|
+
- Show placeholder or blur-up effect
|
|
424
|
+
- Improves initial page load significantly
|
|
425
|
+
|
|
426
|
+
**Critical for ecommerce:**
|
|
427
|
+
- Product listings have 24-100+ images per page
|
|
428
|
+
- Lazy loading reduces initial load by 60-80%
|
|
429
|
+
- Faster perceived performance
|
|
430
|
+
|
|
431
|
+
### Virtual Scrolling (Advanced)
|
|
432
|
+
|
|
433
|
+
**When to use:**
|
|
434
|
+
- Very large catalogs (500+ products visible)
|
|
435
|
+
- Infinite scroll with memory concerns
|
|
436
|
+
- Performance issues with many DOM elements
|
|
437
|
+
|
|
438
|
+
**How it works:**
|
|
439
|
+
- Only render visible products + buffer
|
|
440
|
+
- Reuse DOM elements as user scrolls
|
|
441
|
+
- Maintains scroll position
|
|
442
|
+
- Libraries: react-window, react-virtuoso
|
|
443
|
+
|
|
444
|
+
**Tradeoff:**
|
|
445
|
+
- Complex implementation
|
|
446
|
+
- Better performance for large lists
|
|
447
|
+
- Required for catalogs with 1000+ products loaded
|
|
448
|
+
|
|
449
|
+
### Filter Performance
|
|
450
|
+
|
|
451
|
+
**Optimistic UI:**
|
|
452
|
+
- Update grid immediately (predicted results)
|
|
453
|
+
- Show loading overlay briefly
|
|
454
|
+
- Replace with real results
|
|
455
|
+
- Better perceived performance
|
|
456
|
+
|
|
457
|
+
## Mobile Optimization
|
|
458
|
+
|
|
459
|
+
**Critical mobile patterns:**
|
|
460
|
+
|
|
461
|
+
**2-column grid:**
|
|
462
|
+
- Maximum 2 products per row
|
|
463
|
+
- Larger touch targets
|
|
464
|
+
- Simplified cards (essential info only)
|
|
465
|
+
- Remove hover effects
|
|
466
|
+
|
|
467
|
+
**Filter drawer:**
|
|
468
|
+
- Full-screen or 80% width drawer
|
|
469
|
+
- "Filters" button with badge count
|
|
470
|
+
- Batch apply (don't re-fetch on each change)
|
|
471
|
+
- Clear all at top
|
|
472
|
+
|
|
473
|
+
**Sticky filter/sort bar:**
|
|
474
|
+
- Fixed at top while scrolling
|
|
475
|
+
- Quick access to filters and sorting
|
|
476
|
+
- Shows active filter count
|
|
477
|
+
- Higher engagement rates
|
|
478
|
+
|
|
479
|
+
**Infinite scroll default:**
|
|
480
|
+
- Better mobile UX than pagination
|
|
481
|
+
- Natural scrolling behavior
|
|
482
|
+
- Keep pagination URLs for SEO
|
|
483
|
+
- Handle back button correctly
|
|
484
|
+
|
|
485
|
+
**Performance:**
|
|
486
|
+
- Lazy load images (critical on mobile)
|
|
487
|
+
- Limit initial products (12-24)
|
|
488
|
+
- Optimize image sizes for mobile
|
|
489
|
+
- Fast filter updates (<1s)
|
|
490
|
+
|
|
491
|
+
## Checklist
|
|
492
|
+
|
|
493
|
+
**Essential product listing features:**
|
|
494
|
+
|
|
495
|
+
- [ ] **RECOMMENDED: Product listing built as reusable component**
|
|
496
|
+
- [ ] Reusable component works for: shop all, category pages, search results, sale pages
|
|
497
|
+
- [ ] Component accepts filter parameters (categoryId, searchQuery, promotionId, etc.)
|
|
498
|
+
- [ ] Responsive grid (3-4 columns desktop, 2 mobile)
|
|
499
|
+
- [ ] Decision made: Pagination vs infinite scroll vs load more
|
|
500
|
+
- [ ] Filter pattern selected: Sidebar (desktop) vs drawer (mobile)
|
|
501
|
+
- [ ] Filters fetched from backend dynamically
|
|
502
|
+
- [ ] Filter options show product count
|
|
503
|
+
- [ ] Active filters displayed above grid (removable pills)
|
|
504
|
+
- [ ] "Clear all filters" button prominent
|
|
505
|
+
- [ ] Sorting options (featured, price, newest, bestselling)
|
|
506
|
+
- [ ] Sort updates products without clearing filters
|
|
507
|
+
- [ ] Filters and sort persist in URL (shareable)
|
|
508
|
+
- [ ] Results count displayed ("Showing 1-24 of 156 products")
|
|
509
|
+
- [ ] Empty state: "No products match filters" with suggestions
|
|
510
|
+
- [ ] "Clear all filters" prominent when no results
|
|
511
|
+
- [ ] Product prices displayed correctly (Medusa: as-is, not divided)
|
|
512
|
+
- [ ] Lazy loading for images (Intersection Observer)
|
|
513
|
+
- [ ] Loading state for filter changes (< 1s)
|
|
514
|
+
- [ ] Mobile: Filter drawer with batch apply
|
|
515
|
+
- [ ] Mobile: 2-column grid maximum
|
|
516
|
+
- [ ] Mobile: Sticky filter/sort button
|
|
517
|
+
- [ ] Pagination URLs for SEO (even with infinite scroll)
|
|
518
|
+
- [ ] Back button support (restore filters, scroll position)
|
|
519
|
+
- [ ] Keyboard accessible (tab through filters, enter to apply)
|
|
520
|
+
- [ ] ARIA labels on filters (role="group", aria-label)
|