diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-13 17:02:58 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-13 17:02:58 -0800 |
| commit | 2d1b58d49c99d2cbecc253b655ee583880156f40 (patch) | |
| tree | 88a4c2a33bc950cd6ac744785afc8d1f570d2ddf | |
| parent | 9bea34af348e5ffb614769cd9020b3692b281823 (diff) | |
| download | neko-2d1b58d49c99d2cbecc253b655ee583880156f40.tar.gz neko-2d1b58d49c99d2cbecc253b655ee583880156f40.tar.bz2 neko-2d1b58d49c99d2cbecc253b655ee583880156f40.zip | |
feat(v2): implement search functionality (NK-shpyxh)
| -rw-r--r-- | frontend/src/components/FeedItems.tsx | 12 | ||||
| -rw-r--r-- | frontend/src/components/FeedList.css | 23 | ||||
| -rw-r--r-- | frontend/src/components/FeedList.tsx | 22 |
3 files changed, 54 insertions, 3 deletions
diff --git a/frontend/src/components/FeedItems.tsx b/frontend/src/components/FeedItems.tsx index dcfd867..60b307e 100644 --- a/frontend/src/components/FeedItems.tsx +++ b/frontend/src/components/FeedItems.tsx @@ -38,6 +38,11 @@ export default function FeedItems() { } // Apply filters + const searchQuery = searchParams.get('q'); + if (searchQuery) { + params.append('q', searchQuery); + } + if (filterFn === 'all') { params.append('read_filter', 'all'); } else if (filterFn === 'starred') { @@ -45,7 +50,9 @@ export default function FeedItems() { params.append('read_filter', 'all'); } else { // default to unread - params.append('read_filter', 'unread'); + if (!searchQuery) { + params.append('read_filter', 'unread'); + } } const queryString = params.toString(); @@ -79,7 +86,8 @@ export default function FeedItems() { useEffect(() => { fetchItems(); - }, [feedId, tagName, filterFn]); + setSelectedIndex(-1); + }, [feedId, tagName, filterFn, searchParams]); const [selectedIndex, setSelectedIndex] = useState(-1); diff --git a/frontend/src/components/FeedList.css b/frontend/src/components/FeedList.css index 3b854b5..65c9c53 100644 --- a/frontend/src/components/FeedList.css +++ b/frontend/src/components/FeedList.css @@ -4,6 +4,29 @@ background: transparent; } +.search-section { + margin-bottom: 1.5rem; +} + +.search-form { + display: flex; +} + +.search-input { + width: 100%; + padding: 0.5rem; + border: 1px solid #999; + background: #eee; + font-size: 1rem; + font-family: inherit; +} + +.search-input:focus { + outline: none; + background: white; + border-color: #000; +} + .feed-list h2 { font-size: 1.2rem; margin-bottom: 0.5rem; diff --git a/frontend/src/components/FeedList.tsx b/frontend/src/components/FeedList.tsx index 91d927c..4e7b040 100644 --- a/frontend/src/components/FeedList.tsx +++ b/frontend/src/components/FeedList.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; import type { Feed, Category } from '../types'; import './FeedList.css'; @@ -8,6 +8,15 @@ export default function FeedList() { const [tags, setTags] = useState<Category[]>([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); + const [searchQuery, setSearchQuery] = useState(''); + const navigate = useNavigate(); + + const handleSearch = (e: React.FormEvent) => { + e.preventDefault(); + if (searchQuery.trim()) { + navigate(`/?q=${encodeURIComponent(searchQuery.trim())}`); + } + }; useEffect(() => { Promise.all([ @@ -36,6 +45,17 @@ export default function FeedList() { return ( <div className="feed-list"> + <div className="search-section"> + <form onSubmit={handleSearch} className="search-form"> + <input + type="search" + placeholder="Search items..." + value={searchQuery} + onChange={(e) => setSearchQuery(e.target.value)} + className="search-input" + /> + </form> + </div> <div className="filter-section"> <ul className="filter-list"> <li><Link to="/?filter=unread">Unread</Link></li> |
