Add MarketFuzzySearch component for enhanced product searching

- Introduced a new MarketFuzzySearch component to provide an advanced search interface with keyboard shortcuts, search suggestions, and recent searches functionality.
- Updated MarketPage and StallView to integrate the new fuzzy search component, replacing the previous search input implementations.
- Enhanced search capabilities with configurable options for better user experience and product discovery.

These changes improve the search functionality across the market module, making it easier for users to find products efficiently.
This commit is contained in:
padreug 2025-09-25 23:02:47 +02:00
parent 86d3133978
commit 8aa575ffb1
3 changed files with 470 additions and 34 deletions

View file

@ -78,14 +78,13 @@
<!-- Search and Filter Bar -->
<div class="mb-6 flex flex-col sm:flex-row gap-4">
<div class="flex-1">
<div class="relative">
<Search class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<Input
v-model="searchQuery"
placeholder="Search products in this stall..."
class="pl-10"
/>
</div>
<FuzzySearch
:data="stallProducts"
:options="searchOptions"
placeholder="Search products in this stall..."
@results="handleSearchResults"
class="w-full"
/>
</div>
<div class="flex gap-2">
@ -166,10 +165,12 @@ import {
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { ArrowLeft, Store, Search, Package, Loader2, X } from 'lucide-vue-next'
import { ArrowLeft, Store, Package, Loader2, X } from 'lucide-vue-next'
import FuzzySearch from '@/components/ui/fuzzy-search/FuzzySearch.vue'
import ProductCard from '../components/ProductCard.vue'
import ProductDetailDialog from '../components/ProductDetailDialog.vue'
import type { Product, Stall } from '../types/market'
import type { FuzzySearchOptions } from '@/composables/useFuzzySearch'
const route = useRoute()
const router = useRouter()
@ -177,13 +178,32 @@ const marketStore = useMarketStore()
// State
const isLoading = ref(false)
const searchQuery = ref('')
const searchResults = ref<Product[]>([])
const sortBy = ref('name')
const selectedCategories = ref<string[]>([])
const showProductDetail = ref(false)
const selectedProduct = ref<Product | null>(null)
const logoError = ref(false)
// Fuzzy search configuration for stall products
const searchOptions: FuzzySearchOptions<Product> = {
fuseOptions: {
keys: [
{ name: 'name', weight: 0.8 }, // Product name has highest weight in stall view
{ name: 'description', weight: 0.4 }, // Description is important for specific product search
{ name: 'categories', weight: 0.3 } // Categories for filtering within stall
],
threshold: 0.2, // More strict matching since we're within a single stall
ignoreLocation: true,
findAllMatches: true,
minMatchCharLength: 2,
shouldSort: true
},
resultLimit: 100, // Less restrictive limit for stall view
minSearchLength: 2,
matchAllWhenSearchEmpty: true
}
// Get stall ID from route params
const stallId = computed(() => route.params.stallId as string)
@ -209,18 +229,12 @@ const stallCategories = computed(() => {
// Product count
const productCount = computed(() => stallProducts.value.length)
// Filtered and sorted products
// Filtered and sorted products (using fuzzy search results when available)
const filteredProducts = computed(() => {
let products = [...stallProducts.value]
// Filter by search query
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase()
products = products.filter(p =>
p.name.toLowerCase().includes(query) ||
p.description?.toLowerCase().includes(query)
)
}
// Use search results if available, otherwise use all stall products
let products = searchResults.value.length > 0 || searchResults.value.length === 0
? [...searchResults.value]
: [...stallProducts.value]
// Filter by selected categories
if (selectedCategories.value.length > 0) {
@ -264,7 +278,12 @@ const toggleCategoryFilter = (category: string) => {
const clearFilters = () => {
selectedCategories.value = []
searchQuery.value = ''
searchResults.value = []
}
// Handle fuzzy search results
const handleSearchResults = (results: Product[]) => {
searchResults.value = results
}
const viewProductDetails = (product: Product) => {