# Fuzzy Search Filter System ## Overview The calendar includes a powerful fuzzy search filter system that allows users to quickly find events by typing partial matches of event titles or descriptions. The system dims non-matching events while keeping matching events fully visible, providing instant visual feedback. ## Features - **Real-time fuzzy search** using Fuse.js library - **Visual filtering** with opacity-based dimming (0.2 for non-matches, 1.0 for matches) - **Minimum character threshold** (2 characters) handled by Fuse.js configuration - **Cross-navigation persistence** - filter applies to pre-rendered grids during navigation - **Escape key support** for quick filter clearing - **Performance optimized** with requestAnimationFrame debouncing ## Architecture ### Core Components #### EventFilterManager (`src/managers/EventFilterManager.ts`) Central component responsible for: - Managing search input event listeners - Performing fuzzy search with Fuse.js - Coordinating visual updates across all event containers - Emitting filter change events via EventBus #### CSS-based Visual System ```css /* Dim all events when filter is active */ swp-events-layer[data-filter-active="true"] swp-event { opacity: 0.2; transition: opacity 200ms ease; } /* Keep matching events fully visible */ swp-events-layer[data-filter-active="true"] swp-event[data-matches="true"] { opacity: 1; } ``` #### Pre-rendered Grid Support - NavigationManager listens for `FILTER_CHANGED` events - NavigationRenderer applies filter state to all grid containers - Ensures filter persists when navigating between time periods ### Event Flow 1. **User Input** → Search field receives input 2. **Debounced Processing** → RequestAnimationFrame prevents excessive filtering 3. **Fuzzy Search** → Fuse.js performs search against event titles/descriptions 4. **DOM Updates** → Matching events marked with `data-matches="true"` 5. **CSS Application** → Non-matching events automatically dimmed via CSS rules 6. **Cross-Grid Sync** → Filter applied to all pre-rendered grids ## Configuration ### Fuse.js Settings ```typescript const fuseOptions = { keys: ['title', 'description'], // Search in title and description threshold: 0.3, // 0 = exact match, 1 = match anything includeScore: true, // Include relevance scores minMatchCharLength: 2, // Minimum 2 characters for match shouldSort: true, // Sort by relevance ignoreLocation: true // Search anywhere in string }; ``` ### CSS Variables ```css :root { --filter-dimmed-opacity: 0.2; /* Opacity for non-matching events */ --filter-transition: 200ms ease; /* Smooth opacity transitions */ } ``` ## Integration Points ### CalendarManager ```typescript // EventFilterManager is initialized in CalendarManager constructor this.eventFilterManager = new EventFilterManager(); ``` ### EventRenderer ```typescript // Events emit EVENTS_RENDERED for filter system to track this.eventBus.emit(CoreEvents.EVENTS_RENDERED, { events: events, container: context.container }); ``` ### HTML Structure ```html ``` ## User Experience ### Search Behavior - **No input**: All events visible at full opacity - **1 character**: Filter active, but Fuse.js won't return matches (by design) - **2+ characters**: Real-time fuzzy matching with visual feedback - **Empty field**: Filter cleared, all events return to normal - **Escape key**: Immediate filter clearing ### Visual Feedback - **Search field styling**: Border color changes when filter is active - **Event dimming**: Non-matching events fade to 20% opacity - **Smooth transitions**: 200ms ease transitions for polished feel ## Performance Considerations ### Optimization Strategies 1. **RequestAnimationFrame debouncing** prevents excessive search operations 2. **CSS-based visual updates** leverage browser's rendering pipeline 3. **Event delegation** avoids per-event listener overhead 4. **Efficient DOM queries** using attribute selectors ### Memory Management - Event listeners properly scoped to component lifecycle - Fuse.js instance recreated only when event data changes - Minimal DOM manipulation through attribute-based CSS rules ## Error Handling ### Graceful Degradation - System continues to function if Fuse.js fails to load - Search input remains functional for basic text entry - Console warnings for debugging (removed in production) ### Edge Cases - **No events to search**: Filter system remains inactive - **Empty search results**: All events dimmed (expected behavior) - **DOM timing issues**: Waits for DOM readiness before initialization ## Future Enhancements ### Potential Improvements - **Search result highlighting** within event text - **Advanced filters** (date range, event type, etc.) - **Search history** with dropdown suggestions - **Keyboard navigation** through search results - **Search analytics** for usage insights ### Performance Optimizations - **Virtual scrolling** for large event sets - **Search index caching** for repeated queries - **Web Workers** for heavy search operations ## Dependencies ### External Libraries - **Fuse.js** (v7.x) - Fuzzy search library - License: Apache 2.0 - File: `wwwroot/js/lib/fuse.min.mjs` - Import: ES module format ### Internal Dependencies - **EventBus** - Inter-component communication - **CoreEvents** - Centralized event type definitions - **CalendarEvent** - Event data type definitions ## Testing Considerations ### Test Scenarios 1. **Basic search functionality** - Verify fuzzy matching works 2. **Performance testing** - Large event sets (1000+ events) 3. **Cross-navigation** - Filter persistence during navigation 4. **Edge cases** - Empty results, special characters, very long queries 5. **Accessibility** - Screen reader compatibility, keyboard navigation ### Browser Compatibility - **Modern browsers** with ES modules support - **CSS custom properties** support required - **requestAnimationFrame** API required ## Maintenance Notes ### Code Organization - **Single responsibility** - EventFilterManager handles only filtering - **Event-driven** - Loose coupling via EventBus - **CSS-first** - Visual logic in stylesheets, not JavaScript - **Type-safe** - Full TypeScript implementation ### Common Issues - **Timing**: Ensure EventFilterManager initializes after DOM ready - **Event data**: Verify EVENTS_RENDERED events are emitted correctly - **CSS specificity**: Filter styles must override existing event styles - **Memory leaks**: Properly clean up event listeners in destroy() This fuzzy search filter system provides an intuitive and performant way for users to quickly locate specific events within the calendar interface.