aboutsummaryrefslogtreecommitdiffstats
path: root/frontend
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 17:02:58 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 17:02:58 -0800
commit2d1b58d49c99d2cbecc253b655ee583880156f40 (patch)
tree88a4c2a33bc950cd6ac744785afc8d1f570d2ddf /frontend
parent9bea34af348e5ffb614769cd9020b3692b281823 (diff)
downloadneko-2d1b58d49c99d2cbecc253b655ee583880156f40.tar.gz
neko-2d1b58d49c99d2cbecc253b655ee583880156f40.tar.bz2
neko-2d1b58d49c99d2cbecc253b655ee583880156f40.zip
feat(v2): implement search functionality (NK-shpyxh)
Diffstat (limited to 'frontend')
-rw-r--r--frontend/src/components/FeedItems.tsx12
-rw-r--r--frontend/src/components/FeedList.css23
-rw-r--r--frontend/src/components/FeedList.tsx22
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>