fix: Update private key field in chat integration documentation
- Change the private key field name from "prvkey" to "prvkey_hex" in the CHAT_INTEGRATION.md file for clarity and consistency with expected data formats. feat: Add Fuzzy Search Component and Composable - Introduce a new FuzzySearch component for Vue 3, leveraging Fuse.js for intelligent search capabilities. - Implement a useFuzzySearch composable for flexible search functionality, allowing configuration of search options. - Create demo and README files to showcase usage and features of the fuzzy search implementation. - Update package.json and package-lock.json to include @vueuse/integrations version 13.6.0 for enhanced performance.
This commit is contained in:
parent
37a539bc2d
commit
3d1bc94183
8 changed files with 783 additions and 1 deletions
183
src/composables/useFuzzySearch.ts
Normal file
183
src/composables/useFuzzySearch.ts
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
import { ref, computed, type Ref, type ComputedRef } from 'vue'
|
||||
import { useFuse, type UseFuseOptions, type FuseOptions } from '@vueuse/integrations'
|
||||
import type { FuseResult } from 'fuse.js'
|
||||
|
||||
export interface FuzzySearchOptions<T = any> {
|
||||
/**
|
||||
* Fuse.js options for configuring the search behavior
|
||||
*/
|
||||
fuseOptions?: FuseOptions<T>
|
||||
/**
|
||||
* Maximum number of results to return
|
||||
*/
|
||||
resultLimit?: number
|
||||
/**
|
||||
* Whether to return all items when search is empty
|
||||
*/
|
||||
matchAllWhenSearchEmpty?: boolean
|
||||
/**
|
||||
* Debounce delay in milliseconds for search input
|
||||
*/
|
||||
debounceMs?: number
|
||||
/**
|
||||
* Minimum search length before triggering search
|
||||
*/
|
||||
minSearchLength?: number
|
||||
}
|
||||
|
||||
export interface UseFuzzySearchReturn<T> {
|
||||
/**
|
||||
* Current search query
|
||||
*/
|
||||
searchQuery: Ref<string>
|
||||
/**
|
||||
* Search results with Fuse.js scoring
|
||||
*/
|
||||
results: ComputedRef<FuseResult<T>[]>
|
||||
/**
|
||||
* Filtered items (just the items without scoring)
|
||||
*/
|
||||
filteredItems: ComputedRef<T[]>
|
||||
/**
|
||||
* Whether search is currently active
|
||||
*/
|
||||
isSearching: ComputedRef<boolean>
|
||||
/**
|
||||
* Number of results found
|
||||
*/
|
||||
resultCount: ComputedRef<number>
|
||||
/**
|
||||
* Clear the current search
|
||||
*/
|
||||
clearSearch: () => void
|
||||
/**
|
||||
* Set the search query
|
||||
*/
|
||||
setSearchQuery: (query: string) => void
|
||||
/**
|
||||
* Update the data to search through
|
||||
*/
|
||||
updateData: (data: T[]) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable for fuzzy search functionality using Fuse.js
|
||||
*
|
||||
* @param data - The data to search through
|
||||
* @param options - Configuration options for the fuzzy search
|
||||
* @returns Object with search functionality and results
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Basic usage
|
||||
* const { searchQuery, results, filteredItems, clearSearch } = useFuzzySearch(
|
||||
* products,
|
||||
* {
|
||||
* fuseOptions: {
|
||||
* keys: ['name', 'description'],
|
||||
* threshold: 0.3
|
||||
* },
|
||||
* resultLimit: 10,
|
||||
* minSearchLength: 2
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* // Integration with existing market functionality
|
||||
* const { searchQuery, filteredItems } = useFuzzySearch(
|
||||
* marketStore.products,
|
||||
* {
|
||||
* fuseOptions: {
|
||||
* keys: [
|
||||
* { name: 'name', weight: 0.7 },
|
||||
* { name: 'description', weight: 0.3 },
|
||||
* { name: 'stallName', weight: 0.2 },
|
||||
* { name: 'categories', weight: 0.1 }
|
||||
* ],
|
||||
* threshold: 0.3,
|
||||
* ignoreLocation: true
|
||||
* },
|
||||
* resultLimit: 50,
|
||||
* minSearchLength: 2
|
||||
* }
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
export function useFuzzySearch<T = any>(
|
||||
data: Ref<T[]> | T[],
|
||||
options: FuzzySearchOptions<T> = {}
|
||||
): UseFuzzySearchReturn<T> {
|
||||
const {
|
||||
fuseOptions = {
|
||||
// Default Fuse.js options
|
||||
threshold: 0.3,
|
||||
distance: 100,
|
||||
ignoreLocation: true,
|
||||
useExtendedSearch: false,
|
||||
minMatchCharLength: 1,
|
||||
shouldSort: true,
|
||||
findAllMatches: false,
|
||||
location: 0,
|
||||
isCaseSensitive: false,
|
||||
keys: []
|
||||
},
|
||||
resultLimit,
|
||||
matchAllWhenSearchEmpty = true,
|
||||
debounceMs = 300,
|
||||
minSearchLength = 0
|
||||
} = options
|
||||
|
||||
// Search query state
|
||||
const searchQuery = ref('')
|
||||
|
||||
// Create the Fuse instance using VueUse integration
|
||||
const { results } = useFuse(
|
||||
searchQuery,
|
||||
data,
|
||||
{
|
||||
fuseOptions,
|
||||
resultLimit,
|
||||
matchAllWhenSearchEmpty
|
||||
}
|
||||
)
|
||||
|
||||
// Computed properties
|
||||
const isSearching = computed(() => {
|
||||
const query = searchQuery.value.trim()
|
||||
return query.length >= minSearchLength
|
||||
})
|
||||
|
||||
const filteredItems = computed(() => {
|
||||
return results.value.map(result => result.item)
|
||||
})
|
||||
|
||||
const resultCount = computed(() => results.value.length)
|
||||
|
||||
// Methods
|
||||
const clearSearch = () => {
|
||||
searchQuery.value = ''
|
||||
}
|
||||
|
||||
const setSearchQuery = (query: string) => {
|
||||
searchQuery.value = query
|
||||
}
|
||||
|
||||
const updateData = (newData: T[]) => {
|
||||
// The useFuse composable automatically watches for data changes
|
||||
// so we just need to update the ref if it's reactive
|
||||
if (Array.isArray(data)) {
|
||||
// If data is not reactive, we need to handle this differently
|
||||
console.warn('Data is not reactive. Consider using ref() for the data parameter.')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
searchQuery,
|
||||
results,
|
||||
filteredItems,
|
||||
isSearching,
|
||||
resultCount,
|
||||
clearSearch,
|
||||
setSearchQuery,
|
||||
updateData
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue