aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-15 14:09:45 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-15 14:09:45 -0800
commit94834afbb26b576218a3d84b2187e38708301ba0 (patch)
treeac68774d0df753cd17b4710e446585c9d41d8cb0
parent1d3ad564df8cc09b16172901916bcef9abe31ab4 (diff)
downloadneko-94834afbb26b576218a3d84b2187e38708301ba0.tar.gz
neko-94834afbb26b576218a3d84b2187e38708301ba0.tar.bz2
neko-94834afbb26b576218a3d84b2187e38708301ba0.zip
Frontend: Implement multi-select feeds in sidebar (NK-p0nfoi)
-rw-r--r--frontend/src/components/FeedItems.tsx6
-rw-r--r--frontend/src/components/FeedList.css11
-rw-r--r--frontend/src/components/FeedList.tsx54
3 files changed, 59 insertions, 12 deletions
diff --git a/frontend/src/components/FeedItems.tsx b/frontend/src/components/FeedItems.tsx
index 5220c77..30a0a7f 100644
--- a/frontend/src/components/FeedItems.tsx
+++ b/frontend/src/components/FeedItems.tsx
@@ -30,7 +30,11 @@ export default function FeedItems() {
const params = new URLSearchParams();
if (feedId) {
- params.append('feed_id', feedId);
+ if (feedId.includes(',')) {
+ params.append('feed_ids', feedId);
+ } else {
+ params.append('feed_id', feedId);
+ }
} else if (tagName) {
params.append('tag', tagName);
}
diff --git a/frontend/src/components/FeedList.css b/frontend/src/components/FeedList.css
index c63b426..38a324b 100644
--- a/frontend/src/components/FeedList.css
+++ b/frontend/src/components/FeedList.css
@@ -134,6 +134,17 @@
margin-bottom: 0;
}
+.feed-item-row {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.feed-checkbox {
+ cursor: pointer;
+ margin: 0;
+}
+
.feed-category {
display: none;
}
diff --git a/frontend/src/components/FeedList.tsx b/frontend/src/components/FeedList.tsx
index 4e6738e..556ce6e 100644
--- a/frontend/src/components/FeedList.tsx
+++ b/frontend/src/components/FeedList.tsx
@@ -194,17 +194,49 @@ export default function FeedList({
<p>No feeds found.</p>
) : (
<ul className="feed-list-items">
- {feeds.map((feed) => (
- <li key={feed._id} className="sidebar-feed-item">
- <Link
- to={getNavPath(`/feed/${feed._id}`)}
- className={`feed-title ${feedId === String(feed._id) ? 'active' : ''}`}
- onClick={handleLinkClick}
- >
- {feed.title || feed.url}
- </Link>
- </li>
- ))}
+ {feeds.map((feed) => {
+ const isSelected = feedId?.split(',').includes(String(feed._id));
+
+ const toggleFeed = (e: React.MouseEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ const selectedIds = feedId ? feedId.split(',') : [];
+ let newIds;
+ if (isSelected) {
+ newIds = selectedIds.filter(id => id !== String(feed._id));
+ } else {
+ newIds = [...selectedIds, String(feed._id)];
+ }
+
+ if (newIds.length === 0) {
+ navigate(getNavPath('/'));
+ } else {
+ navigate(getNavPath(`/feed/${newIds.join(',')}`));
+ }
+ };
+
+ return (
+ <li key={feed._id} className="sidebar-feed-item">
+ <div className="feed-item-row">
+ <input
+ type="checkbox"
+ checked={!!isSelected}
+ onChange={() => { }} // Controlled by div click for better hit area
+ onClick={toggleFeed}
+ className="feed-checkbox"
+ />
+ <Link
+ to={getNavPath(`/feed/${feed._id}`)}
+ className={`feed-title ${isSelected ? 'active' : ''}`}
+ onClick={handleLinkClick}
+ >
+ {feed.title || feed.url}
+ </Link>
+ </div>
+ </li>
+ );
+ })}
</ul>
))}
</div>