feat: extract and consolidate common UI patterns across market module
## Component Extraction
- Create MarketSearchBar component with dual-mode support (enhanced/simple)
- Enhanced mode: suggestions, keyboard shortcuts, category filters
- Simple mode: basic search functionality
- Dynamic imports for performance optimization
- Extract LoadingErrorState component for consistent loading/error handling
- Configurable compact/full modes with custom messages
- Built-in retry functionality
- Standardized spinner and error displays
- Consolidate CartButton component (already extracted in previous commit)
## UI Standardization
- Replace inline category badges in StallView with CategoryFilterBar component
- Add missing state management for category filtering (filterMode, setFilterMode)
- Ensure consistent filtering UI between MarketPage and StallView
- Standardize loading states across MarketPage, ProductGrid, and MerchantStore
## Code Organization
- MarketPage: Uses enhanced MarketSearchBar with full feature set
- StallView: Uses simple MarketSearchBar for cleaner stall-specific search
- Both views now share CategoryFilterBar, CartButton, and ProductGrid
- LoadingErrorState provides unified loading/error UX patterns
## Technical Improvements
- Eliminate code duplication following DRY principles
- Improve maintainability with single source of truth for UI patterns
- Optimize performance with conditional feature loading
- Enhance accessibility with consistent keyboard shortcuts and ARIA labels
- Ensure mobile-responsive designs with unified behavior
BREAKING CHANGE: MarketFuzzySearch component replaced by MarketSearchBar
This commit is contained in:
parent
8821f604be
commit
c8860dc937
6 changed files with 586 additions and 94 deletions
|
|
@ -1,24 +1,22 @@
|
|||
<template>
|
||||
<div class="product-grid-container">
|
||||
<!-- Loading State -->
|
||||
<div v-if="isLoading" class="flex justify-center items-center min-h-64">
|
||||
<div class="flex flex-col items-center space-y-4">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
||||
<p class="text-gray-600">{{ loadingMessage }}</p>
|
||||
<LoadingErrorState
|
||||
:is-loading="isLoading"
|
||||
:loading-message="loadingMessage"
|
||||
:has-error="false"
|
||||
:full-height="false"
|
||||
>
|
||||
<!-- Empty State -->
|
||||
<div v-if="products.length === 0" class="text-center py-12">
|
||||
<slot name="empty">
|
||||
<EmptyIcon class="w-24 h-24 text-muted-foreground/50 mx-auto mb-4" />
|
||||
<h3 class="text-xl font-semibold text-gray-600 mb-2">{{ emptyTitle }}</h3>
|
||||
<p class="text-gray-500">{{ emptyMessage }}</p>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div v-else-if="products.length === 0 && !isLoading" class="text-center py-12">
|
||||
<slot name="empty">
|
||||
<EmptyIcon class="w-24 h-24 text-muted-foreground/50 mx-auto mb-4" />
|
||||
<h3 class="text-xl font-semibold text-gray-600 mb-2">{{ emptyTitle }}</h3>
|
||||
<p class="text-gray-500">{{ emptyMessage }}</p>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<!-- Product Grid -->
|
||||
<div v-else :class="gridClasses">
|
||||
<!-- Product Grid -->
|
||||
<div v-else :class="gridClasses">
|
||||
<ProductCard
|
||||
v-for="product in products"
|
||||
:key="product.id"
|
||||
|
|
@ -27,16 +25,17 @@
|
|||
@view-details="handleViewDetails"
|
||||
@view-stall="$emit('view-stall', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Product Detail Dialog - Now managed internally -->
|
||||
<ProductDetailDialog
|
||||
v-if="selectedProduct"
|
||||
:product="selectedProduct"
|
||||
:isOpen="showProductDetail"
|
||||
@close="closeProductDetail"
|
||||
@add-to-cart="handleDialogAddToCart"
|
||||
/>
|
||||
<!-- Product Detail Dialog - Now managed internally -->
|
||||
<ProductDetailDialog
|
||||
v-if="selectedProduct"
|
||||
:product="selectedProduct"
|
||||
:isOpen="showProductDetail"
|
||||
@close="closeProductDetail"
|
||||
@add-to-cart="handleDialogAddToCart"
|
||||
/>
|
||||
</LoadingErrorState>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -45,6 +44,7 @@ import { computed, ref } from 'vue'
|
|||
import { Package as EmptyIcon } from 'lucide-vue-next'
|
||||
import ProductCard from './ProductCard.vue'
|
||||
import ProductDetailDialog from './ProductDetailDialog.vue'
|
||||
import LoadingErrorState from './LoadingErrorState.vue'
|
||||
import type { Product } from '../types/market'
|
||||
|
||||
interface Props {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue