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
|
|
@ -58,35 +58,33 @@
|
|||
</Badge>
|
||||
</div>
|
||||
|
||||
<!-- Categories (Enhanced) -->
|
||||
<div v-if="stallCategories.length > 0" class="flex flex-wrap gap-1">
|
||||
<Badge
|
||||
v-for="category in stallCategories"
|
||||
:key="category"
|
||||
:variant="selectedCategories.includes(category) ? 'default' : 'secondary'"
|
||||
class="text-xs px-2 py-0.5 cursor-pointer transition-all duration-200 hover:scale-105 hover:shadow-sm"
|
||||
:class="{
|
||||
'bg-gradient-to-r from-primary to-primary/90 text-primary-foreground shadow-md': selectedCategories.includes(category),
|
||||
'hover:bg-primary/10 hover:border-primary/50': !selectedCategories.includes(category)
|
||||
}"
|
||||
@click="toggleCategoryFilter(category)"
|
||||
>
|
||||
{{ category }}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<!-- Category Filter Bar -->
|
||||
<CategoryFilterBar
|
||||
v-if="stallCategories.length > 0"
|
||||
:categories="stallCategories"
|
||||
:selected-categories="selectedCategories"
|
||||
:filter-mode="filterMode"
|
||||
title="Categories"
|
||||
@toggle-category="toggleCategoryFilter"
|
||||
@set-filter-mode="setFilterMode"
|
||||
@clear-filters="clearCategoryFilters"
|
||||
class="mb-4 sm:mb-6"
|
||||
/>
|
||||
|
||||
<!-- Search and Filter Bar -->
|
||||
<div class="mb-4 sm:mb-6 flex flex-col sm:flex-row gap-2 sm:gap-4">
|
||||
<div class="flex-1">
|
||||
<FuzzySearch
|
||||
<MarketSearchBar
|
||||
:data="stallProducts"
|
||||
:options="searchOptions"
|
||||
placeholder="Search products in this stall..."
|
||||
:show-enhancements="false"
|
||||
@results="handleSearchResults"
|
||||
class="w-full"
|
||||
/>
|
||||
|
|
@ -151,9 +149,10 @@ import {
|
|||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { ArrowLeft, Store, X } from 'lucide-vue-next'
|
||||
import FuzzySearch from '@/components/ui/fuzzy-search/FuzzySearch.vue'
|
||||
import MarketSearchBar from '../components/MarketSearchBar.vue'
|
||||
import ProductGrid from '../components/ProductGrid.vue'
|
||||
import CartButton from '../components/CartButton.vue'
|
||||
import CategoryFilterBar from '../components/CategoryFilterBar.vue'
|
||||
import type { Product, Stall } from '../types/market'
|
||||
import type { FuzzySearchOptions } from '@/composables/useFuzzySearch'
|
||||
|
||||
|
|
@ -167,6 +166,7 @@ const searchResults = ref<Product[]>([])
|
|||
const searchQuery = ref('')
|
||||
const sortBy = ref('name')
|
||||
const selectedCategories = ref<string[]>([])
|
||||
const filterMode = ref<'any' | 'all'>('any')
|
||||
const logoError = ref(false)
|
||||
|
||||
// Fuzzy search configuration for stall products
|
||||
|
|
@ -260,6 +260,14 @@ const toggleCategoryFilter = (category: string) => {
|
|||
}
|
||||
}
|
||||
|
||||
const setFilterMode = (mode: 'any' | 'all') => {
|
||||
filterMode.value = mode
|
||||
}
|
||||
|
||||
const clearCategoryFilters = () => {
|
||||
selectedCategories.value = []
|
||||
}
|
||||
|
||||
const clearFilters = () => {
|
||||
selectedCategories.value = []
|
||||
searchResults.value = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue