From ad6b8187e5a7ba6b36f330b181434e4582bf2d74 Mon Sep 17 00:00:00 2001
From: Adam Mathes <adam@adammathes.com>
Date: Sat, 14 Feb 2026 16:05:56 -0800
Subject: UI: Add collapsible caret icons for Tags and Feeds in sidebar
 (NK-gjymiw)

---
 frontend/src/components/FeedList.tsx | 51 ++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 17 deletions(-)

(limited to 'frontend/src/components/FeedList.tsx')

diff --git a/frontend/src/components/FeedList.tsx b/frontend/src/components/FeedList.tsx
index 250ce7d..a4ecccf 100644
--- a/frontend/src/components/FeedList.tsx
+++ b/frontend/src/components/FeedList.tsx
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
 import { Link, useNavigate, useSearchParams, useLocation, useParams } from 'react-router-dom';
 import type { Feed, Category } from '../types';
 import './FeedList.css';
+import './FeedListVariants.css';
 import { apiFetch } from '../utils';
 
 export default function FeedList({
@@ -20,12 +21,22 @@ export default function FeedList({
   const [loading, setLoading] = useState(true);
   const [error, setError] = useState('');
   const [feedsExpanded, setFeedsExpanded] = useState(false);
+  const [tagsExpanded, setTagsExpanded] = useState(true);
   const [searchQuery, setSearchQuery] = useState('');
   const navigate = useNavigate();
   const [searchParams] = useSearchParams();
   const location = useLocation();
   const { feedId, tagName } = useParams();
 
+  const sidebarVariant = searchParams.get('sidebar') || localStorage.getItem('neko-sidebar-variant') || 'glass';
+
+  useEffect(() => {
+    const variant = searchParams.get('sidebar');
+    if (variant) {
+      localStorage.setItem('neko-sidebar-variant', variant);
+    }
+  }, [searchParams]);
+
   const currentFilter =
     searchParams.get('filter') ||
     (location.pathname === '/' && !feedId && !tagName ? 'unread' : '');
@@ -41,6 +52,10 @@ export default function FeedList({
     setFeedsExpanded(!feedsExpanded);
   };
 
+  const toggleTags = () => {
+    setTagsExpanded(!tagsExpanded);
+  };
+
   const handleLinkClick = () => {
     if (isMobile) {
       setSidebarVisible(false);
@@ -77,7 +92,7 @@ export default function FeedList({
   };
 
   return (
-    <div className="feed-list">
+    <div className={`feed-list variant-${sidebarVariant}`}>
       <h1 className="logo" onClick={() => setSidebarVisible(false)}>
         🐱
       </h1>
@@ -115,27 +130,29 @@ export default function FeedList({
       </div>
 
       <div className="tag-section">
-        <h4 onClick={() => { }} className="section-header">
-          Tags
+        <h4 onClick={toggleTags} className="section-header">
+          <span className={`caret ${tagsExpanded ? 'expanded' : ''}`}>▶</span> Tags
         </h4>
-        <ul className="tag-list-items">
-          {tags.map((tag) => (
-            <li key={tag.title} className="tag-item">
-              <Link
-                to={`/tag/${encodeURIComponent(tag.title)}`}
-                className={`tag-link ${tagName === tag.title ? 'active' : ''}`}
-                onClick={handleLinkClick}
-              >
-                {tag.title}
-              </Link>
-            </li>
-          ))}
-        </ul>
+        {tagsExpanded && (
+          <ul className="tag-list-items">
+            {tags.map((tag) => (
+              <li key={tag.title} className="tag-item">
+                <Link
+                  to={`/tag/${encodeURIComponent(tag.title)}`}
+                  className={`tag-link ${tagName === tag.title ? 'active' : ''}`}
+                  onClick={handleLinkClick}
+                >
+                  {tag.title}
+                </Link>
+              </li>
+            ))}
+          </ul>
+        )}
       </div>
 
       <div className="feed-section">
         <h4 onClick={toggleFeeds} className="section-header">
-          Feeds
+          <span className={`caret ${feedsExpanded ? 'expanded' : ''}`}>▶</span> Feeds
         </h4>
         {feedsExpanded &&
           (feeds.length === 0 ? (
-- 
cgit v1.2.3

