diff --git a/src/modules/market/components/CartButton.vue b/src/modules/market/components/CartButton.vue new file mode 100644 index 0000000..6377564 --- /dev/null +++ b/src/modules/market/components/CartButton.vue @@ -0,0 +1,23 @@ + + + \ No newline at end of file diff --git a/src/modules/market/composables/useSearchKeyboardShortcuts.ts b/src/modules/market/composables/useSearchKeyboardShortcuts.ts new file mode 100644 index 0000000..b0bcfb0 --- /dev/null +++ b/src/modules/market/composables/useSearchKeyboardShortcuts.ts @@ -0,0 +1,53 @@ +import { onMounted, onUnmounted, type Ref } from 'vue' + +export function useSearchKeyboardShortcuts(searchInputRef: Ref) { + const focusSearchInput = () => { + if (searchInputRef.value?.$el) { + // Access the underlying HTML input element from the Shadcn Input component + const inputElement = searchInputRef.value.$el.querySelector('input') || searchInputRef.value.$el + if (inputElement && typeof inputElement.focus === 'function') { + inputElement.focus() + } + } + } + + const blurSearchInput = () => { + if (searchInputRef.value?.$el) { + const inputElement = searchInputRef.value.$el.querySelector('input') || searchInputRef.value.$el + if (inputElement && typeof inputElement.blur === 'function') { + inputElement.blur() + } + } + } + + const handleGlobalKeydown = (event: KeyboardEvent) => { + // โŒ˜K or Ctrl+K to focus search + if ((event.metaKey || event.ctrlKey) && event.key === 'k') { + event.preventDefault() + focusSearchInput() + } + } + + const handleSearchKeydown = (event: KeyboardEvent) => { + // Escape key clears search or blurs input + if (event.key === 'Escape') { + event.preventDefault() + return true // Signal to clear search + } + return false + } + + onMounted(() => { + document.addEventListener('keydown', handleGlobalKeydown) + }) + + onUnmounted(() => { + document.removeEventListener('keydown', handleGlobalKeydown) + }) + + return { + focusSearchInput, + blurSearchInput, + handleSearchKeydown + } +} \ No newline at end of file diff --git a/src/modules/market/docs/category-filter-improvements.md b/src/modules/market/docs/category-filter-improvements.md new file mode 100644 index 0000000..3fcf6ab --- /dev/null +++ b/src/modules/market/docs/category-filter-improvements.md @@ -0,0 +1,430 @@ +# Category Filter System - Future Improvements + +This document outlines potential enhancements to the category filtering system based on user needs and advanced UX patterns. + +## ๐ŸŽฏ Current Implementation Status + +โœ… **Completed:** +- Reusable `useCategoryFilter` composable +- Set-based performance optimizations +- Full accessibility (ARIA, keyboard navigation, screen readers) +- Theme-aware semantic styling +- Proper Nostr event tag extraction (`'t'` tags) +- Real-time reactive filtering + +## ๐Ÿš€ Proposed Future Improvements + +### 1. **Advanced Filtering Logic** + +#### ~~AND/OR Filter Modes~~ +โœ… impemented! + +Currently uses OR logic (show products with ANY selected category). Add support for AND logic. + +```typescript +interface AdvancedFilterOptions { + mode: 'any' | 'all' // OR vs AND logic + caseSensitive: boolean + includeEmpty: boolean + minCount: number + maxSelections?: number // Limit concurrent selections +} +``` + +**Benefits:** +- More precise filtering for power users +- Better product discovery in large catalogs + +**Implementation:** +```typescript +// In useCategoryFilter.ts +const filteredProducts = computed(() => { + // ... existing code + + return products.value.filter(product => { + const matches = product.categories?.filter(cat => + selectedCategories.value.has(cat.toLowerCase()) + ) || [] + + return options.mode === 'any' + ? matches.length > 0 + : matches.length === selectedCategories.value.size + }) +}) +``` + +--- + +### 2. **Hierarchical Categories** + +Support nested category structures for better organization. + +```typescript +interface HierarchicalCategory { + id: string + name: string + parent?: string + children?: string[] + level: number + path: string[] // e.g., ['Electronics', 'Computers', 'Laptops'] +} +``` + +**UI Enhancement:** +- Expandable tree structure +- Breadcrumb navigation +- Parent/child selection logic + +**Example:** +``` +๐Ÿ“ Electronics (25) + โ””โ”€โ”€ ๐Ÿ’ป Computers (12) + โ””โ”€โ”€ ๐Ÿ’พ Storage (5) + โ””โ”€โ”€ ๐Ÿ“ฑ Mobile (13) +๐Ÿ“ Clothing (18) + โ””โ”€โ”€ ๐Ÿ‘• Shirts (8) + โ””โ”€โ”€ ๐Ÿ‘– Pants (10) +``` + +--- + +### 3. **Search Within Categories** + +Add search functionality for large category lists. + +```vue + +``` + +**Features:** +- Fuzzy search within category names +- Highlight matching text +- Keyboard navigation through results + +--- + +### 4. **Category Metadata & Visualization** + +Enhance categories with rich metadata and visual cues. + +```typescript +interface EnhancedCategoryItem { + category: string + count: number + selected: boolean + metadata?: { + color?: string // Brand color for visual consistency + icon?: string // Lucide icon name or emoji + description?: string // Tooltip description + trending?: boolean // Popular/trending indicator + new?: boolean // Recently added categories + } +} +``` + +**Visual Enhancements:** +```vue + + + {{ category.category }} + + +``` + +--- + +### 5. **Persistent Filter State** + +Remember user preferences across sessions. + +```typescript +// composables/usePersistentCategoryFilter.ts +export function usePersistentCategoryFilter() { + const storageKey = 'market-category-filters' + + const savedFilters = useLocalStorage(storageKey, { + selectedCategories: [] as string[], + filterMode: 'any' as 'any' | 'all', + sortPreference: 'popularity' as 'popularity' | 'alphabetical' + }) + + return { + savedFilters, + saveCurrentState, + restoreState, + clearSavedState + } +} +``` + +**Features:** +- Remember selected categories +- Save filter preferences (AND/OR mode) +- Cross-device sync (if user is authenticated) + +--- + +### 6. **Smart Categories & Auto-suggestions** + +AI-powered category suggestions and smart filtering. + +```typescript +interface SmartCategoryFeatures { + suggestCategories: (searchQuery: string) => string[] + relatedCategories: (selectedCategory: string) => string[] + popularCombinations: () => string[][] + seasonalRecommendations: () => string[] +} +``` + +**Implementation Ideas:** +- "Users who selected X also selected Y" +- Seasonal category promotion (winter โ†’ clothing, electronics) +- Search query to category mapping + +--- + +### 7. **Advanced UI Patterns** + +#### Multi-Column Layout +For markets with many categories: + +```vue +
+ +
+``` + +#### Collapsible Groups +Group categories by type with expand/collapse: + +```vue +
+ + {{ group.name }} ({{ group.totalCount }}) + +
+ +
+
+``` + +#### Tag Cloud Visualization +Show categories sized by popularity: + +```vue +
+ +
+``` + +--- + +### 8. **Performance Optimizations** + +#### Virtual Scrolling +For markets with 100+ categories: + +```vue + + + +``` + +#### Web Workers +For heavy category processing: + +```typescript +// workers/categoryProcessor.ts +self.onmessage = function(e) { + const { products, options } = e.data + const categoryMap = processCategoriesInWorker(products, options) + self.postMessage(categoryMap) +} + +// In composable +const categoryWorker = new Worker('/workers/categoryProcessor.js') +``` + +--- + +### 9. **Analytics & Insights** + +Track category usage for business intelligence: + +```typescript +interface CategoryAnalytics { + trackCategorySelection: (category: string) => void + trackFilterCombination: (categories: string[]) => void + trackSearchPatterns: (query: string, results: number) => void + generateInsights: () => { + popularCategories: string[] + unusedCategories: string[] + conversionByCategory: Record + } +} +``` + +--- + +### 10. **Mobile-First Enhancements** + +#### Bottom Sheet Interface +Mobile-optimized category selector: + +```vue + + + + Filter by Category + + + + + + + + + +``` + +#### Swipe Gestures +```vue + +``` + +--- + +## ๐Ÿ› ๏ธ Implementation Priority + +### **Phase 1: Essential UX** (2-3 days) +1. โœ… AND/OR filter modes +2. โœ… Persistent filter state +3. โœ… Mobile bottom sheet interface + +### **Phase 2: Advanced Features** (1-2 weeks) +1. ๐Ÿ”„ Hierarchical categories +2. ๐Ÿ”„ Category search functionality +3. ๐Ÿ”„ Smart suggestions + +### **Phase 3: Enterprise Features** (2-3 weeks) +1. ๐Ÿ”„ Analytics & insights +2. ๐Ÿ”„ Virtual scrolling +3. ๐Ÿ”„ Web worker optimizations + +### **Phase 4: Polish** (1 week) +1. ๐Ÿ”„ Enhanced visualizations +2. ๐Ÿ”„ Advanced animations +3. ๐Ÿ”„ A11y improvements + +--- + +## ๐Ÿงช Testing Strategy + +### **Unit Tests** +```typescript +// tests/useCategoryFilter.test.ts +describe('useCategoryFilter', () => { + test('should handle AND/OR filter modes', () => { + // Test implementation + }) + + test('should persist selected categories', () => { + // Test localStorage integration + }) +}) +``` + +### **E2E Tests** +```typescript +// e2e/category-filtering.spec.ts +test('category filtering workflow', async ({ page }) => { + await page.goto('/market') + + // Test category selection + await page.click('[data-testid="category-electronics"]') + await expect(page.locator('[data-testid="product-grid"]')).toContainText('Electronics') + + // Test filter persistence + await page.reload() + await expect(page.locator('[data-testid="category-electronics"]')).toHaveClass(/selected/) +}) +``` + +--- + +## ๐Ÿ“Š Success Metrics + +### **Performance Metrics** +- Category rendering time < 100ms +- Filter application time < 50ms +- Memory usage < 10MB for 1000+ categories + +### **UX Metrics** +- Category selection rate > 60% +- Filter abandonment rate < 10% +- Mobile usability score > 95% + +### **Business Metrics** +- Product discovery improvement +- Conversion rate by category +- User engagement with filtering features + +--- + +## ๐Ÿ”— Related Documentation + +- [Vue 3 Composition API Guide](https://vuejs.org/guide/extras/composition-api-faq.html) +- [VueUse Composables](https://vueuse.org/) +- [Accessibility Guidelines (WCAG 2.1)](https://www.w3.org/WAI/WCAG21/quickref/) +- [Nostr NIP Standards](https://github.com/nostr-protocol/nips) + +--- + +*Last updated: $(date +%Y-%m-%d)* +*Next review: 2024-02-01* \ No newline at end of file diff --git a/src/modules/market/views/MarketPage.vue b/src/modules/market/views/MarketPage.vue index 82de5cb..f5b7081 100644 --- a/src/modules/market/views/MarketPage.vue +++ b/src/modules/market/views/MarketPage.vue @@ -81,15 +81,11 @@ @view-stall="viewStall" /> - -
- -
+ + + @@ -103,10 +99,10 @@ import { useCategoryFilter } from '../composables/useCategoryFilter' import { config } from '@/lib/config' import { Button } from '@/components/ui/button' import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' -import { ShoppingCart } from 'lucide-vue-next' import MarketFuzzySearch from '../components/MarketFuzzySearch.vue' import ProductGrid from '../components/ProductGrid.vue' import CategoryFilterBar from '../components/CategoryFilterBar.vue' +import CartButton from '../components/CartButton.vue' import type { Product } from '../types/market' import type { FuzzySearchOptions } from '@/composables/useFuzzySearch' @@ -249,10 +245,6 @@ const viewStall = (stallId: string) => { router.push(`/market/stall/${stallId}`) } -const viewCart = () => { - router.push('/cart') -} - // Handle fuzzy search results const handleSearchResults = (results: Product[]) => { searchResults.value = results diff --git a/src/modules/market/views/StallView.vue b/src/modules/market/views/StallView.vue index 28425e8..fa7c33e 100644 --- a/src/modules/market/views/StallView.vue +++ b/src/modules/market/views/StallView.vue @@ -130,14 +130,10 @@ @add-to-cart="handleAddToCart" /> - -
- -
+ + +