{# Product Grid ============ Responsive grid layout for product listings. Includes loading skeletons and empty state. Parameters: - products_var: Alpine.js variable containing products array (default: 'products') - loading_var: Alpine.js variable for loading state (default: 'loading') - columns: Dict with breakpoint column counts (default: {sm: 2, md: 3, lg: 4}) - gap: Gap size 'sm' | 'md' | 'lg' (default: 'md') - card_size: Product card size 'sm' | 'md' | 'lg' (default: 'md') - show_rating: Pass to product cards (default: true) - show_quick_add: Pass to product cards (default: true) - show_wishlist: Pass to product cards (default: true) - show_store: Pass to product cards (default: false) - empty_title: Title for empty state (default: 'No products found') - empty_message: Message for empty state (default: 'Try adjusting your filters') - empty_icon: Icon for empty state (default: 'shopping-bag') Usage: {% from 'shared/macros/storefront/product-grid.html' import product_grid, product_grid_skeleton %} {{ product_grid() }} {# With custom columns #} {{ product_grid(columns={'sm': 1, 'md': 2, 'lg': 3}) }} #} {% macro product_grid( products_var='products', loading_var='loading', columns=none, gap='md', card_size='md', show_rating=true, show_quick_add=true, show_wishlist=true, show_store=false, empty_title='No products found', empty_message='Try adjusting your filters or search terms', empty_icon='shopping-bag' ) %} {% from 'shared/macros/storefront/product-card.html' import product_card %} {% set cols = columns if columns else {'sm': 2, 'md': 3, 'lg': 4} %} {% set gaps = {'sm': 'gap-3', 'md': 'gap-4', 'lg': 'gap-6'} %} {# Loading State #}
{{ empty_message }}