From c7bd634ad6ba1870f0f0e296fa502f048c01712f Mon Sep 17 00:00:00 2001 From: chelsea Date: Sat, 11 Oct 2025 19:47:04 -0500 Subject: [PATCH] Add search functionality (Issue #3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend changes: - Added search query parameter (q) to /api/posts endpoint - Search filters posts by title, content, author, and source - Case-insensitive search with substring matching Frontend changes: - Made search bar functional with Enter key and click support - Added performSearch() function to trigger searches - Added Clear Search button that appears during active search - Search results update feed title to show query - Integrated search with existing pagination and filtering - Preserves anonymous/authenticated feed title when clearing search 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app.py | 17 ++++++++++- templates/dashboard.html | 62 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/app.py b/app.py index 4c8e498..c2298a3 100644 --- a/app.py +++ b/app.py @@ -348,6 +348,7 @@ def api_posts(): per_page = int(request.args.get('per_page', DEFAULT_PAGE_SIZE)) community = request.args.get('community', '') platform = request.args.get('platform', '') + search_query = request.args.get('q', '').lower().strip() # Use cached data for better performance cached_posts, cached_comments = _load_posts_cache() @@ -363,7 +364,21 @@ def api_posts(): # Apply platform filter if platform and post_data.get('platform', '').lower() != platform.lower(): continue - + + # Apply search filter + if search_query: + # Search in title, content, author, and source + title = post_data.get('title', '').lower() + content = post_data.get('content', '').lower() + author = post_data.get('author', '').lower() + source = post_data.get('source', '').lower() + + if not (search_query in title or + search_query in content or + search_query in author or + search_query in source): + continue + # Get comment count from cache comment_count = len(cached_comments.get(post_uuid, [])) diff --git a/templates/dashboard.html b/templates/dashboard.html index ccf4b99..c13b1e8 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -447,6 +447,24 @@ transform: translateY(-1px); } +.clear-search-btn { + background: #f1f5f9; + color: #64748b; + border: 1px solid #e2e8f0; + padding: 10px 20px; + border-radius: 8px; + cursor: pointer; + font-size: 14px; + font-weight: 500; + transition: all 0.2s ease; +} + +.clear-search-btn:hover { + background: #e2e8f0; + color: #2c3e50; + transform: translateY(-1px); +} + .feed-container { padding: 0; } @@ -803,6 +821,7 @@ async function loadPosts(page = 1, community = '', platform = '', append = false params.append('per_page', 20); if (community) params.append('community', community); if (platform) params.append('platform', platform); + if (currentSearchQuery) params.append('q', currentSearchQuery); const response = await fetch(`/api/posts?${params}`); const data = await response.json(); @@ -1037,15 +1056,52 @@ function refreshFeed() { } // Search functionality +let currentSearchQuery = ''; + document.querySelector('.search-input').addEventListener('keypress', function(e) { if (e.key === 'Enter') { const query = this.value.trim(); - if (query) { - alert(`Search functionality coming soon! You searched for: "${query}"`); - } + performSearch(query); } }); +document.querySelector('.search-btn').addEventListener('click', function() { + const query = document.querySelector('.search-input').value.trim(); + performSearch(query); +}); + +function performSearch(query) { + currentSearchQuery = query; + currentPage = 1; + + if (query) { + document.querySelector('.content-header h1').textContent = `Search results for "${query}"`; + // Show clear search button + if (!document.querySelector('.clear-search-btn')) { + const clearBtn = document.createElement('button'); + clearBtn.className = 'clear-search-btn'; + clearBtn.textContent = '✕ Clear search'; + clearBtn.onclick = clearSearch; + document.querySelector('.content-actions').prepend(clearBtn); + } + } + + loadPosts(); +} + +function clearSearch() { + currentSearchQuery = ''; + document.querySelector('.search-input').value = ''; + // Restore original feed title based on user state + const isAnonymous = {{ 'true' if anonymous else 'false' }}; + document.querySelector('.content-header h1').textContent = isAnonymous ? 'Public Feed' : 'Your Feed'; + const clearBtn = document.querySelector('.clear-search-btn'); + if (clearBtn) { + clearBtn.remove(); + } + loadPosts(); +} + // Setup infinite scroll functionality function setupInfiniteScroll() { if (!userSettings?.experience?.infinite_scroll) {