From ca4bea084ad4cb1d57fa61369a871e82859e1c72 Mon Sep 17 00:00:00 2001 From: Garret Patti <42485635+garretpatti@users.noreply.github.com> Date: Sun, 5 Apr 2026 16:29:49 -0400 Subject: [PATCH] make FilterPanel hideable and responsive across all library views Adds a toggle button to show/hide the filter panel in Movies, Games, Mixed, and TV views. On mobile the layout stacks vertically (filter above content); on md+ it returns to the side-by-side layout. The toggle button highlights when filters are active so hidden filters remain discoverable. Also fixes a layout bug where items-start on the flex-col container caused MixedView thumbnails to collapse on narrow screens. Co-Authored-By: Claude Sonnet 4.6 --- src/components/games/GamesView.tsx | 47 +++++++++++++++++++------- src/components/mixed/ImageLightbox.tsx | 7 ++-- src/components/mixed/MixedView.tsx | 47 +++++++++++++++++++------- src/components/movies/MoviesView.tsx | 47 +++++++++++++++++++------- src/components/tv/TvView.tsx | 47 +++++++++++++++++++------- 5 files changed, 140 insertions(+), 55 deletions(-) diff --git a/src/components/games/GamesView.tsx b/src/components/games/GamesView.tsx index 0b2a266..d4a0d04 100644 --- a/src/components/games/GamesView.tsx +++ b/src/components/games/GamesView.tsx @@ -21,6 +21,7 @@ export default function GamesView({ libraryId }: Props) { const [selectedTagIds, setSelectedTagIds] = useState>(new Set()) const [assignments, setAssignments] = useState>({}) const [filterRefreshKey, setFilterRefreshKey] = useState(0) + const [showFilters, setShowFilters] = useState(true) const toggleTag = (tagId: string) => setSelectedTagIds((prev) => { @@ -83,20 +84,39 @@ export default function GamesView({ libraryId }: Props) { return true }) + const filtersActive = search !== '' || selectedTagIds.size > 0 + return ( -
-
- + <> +
+
-
+
+ {showFilters && ( +
+ +
+ )} +
{/* Breadcrumb when inside a series */} {selectedSeries && (
@@ -154,8 +174,9 @@ export default function GamesView({ libraryId }: Props) { onCoverUploaded={() => fetchGames(true)} /> )} +
-
+ ) } diff --git a/src/components/mixed/ImageLightbox.tsx b/src/components/mixed/ImageLightbox.tsx index 7db86f5..a474cc7 100644 --- a/src/components/mixed/ImageLightbox.tsx +++ b/src/components/mixed/ImageLightbox.tsx @@ -49,10 +49,11 @@ export default function ImageLightbox({ url, name, onClose, mediaKey, onTagsChan {mediaKey && (
-
+
+ {showFilters && ( +
+ +
+ )} +
{/* Breadcrumb */}
)} +
-
+ ) } diff --git a/src/components/movies/MoviesView.tsx b/src/components/movies/MoviesView.tsx index a19778b..27739eb 100644 --- a/src/components/movies/MoviesView.tsx +++ b/src/components/movies/MoviesView.tsx @@ -18,6 +18,7 @@ export default function MoviesView({ libraryId }: Props) { const [selectedTagIds, setSelectedTagIds] = useState>(new Set()) const [assignments, setAssignments] = useState>({}) const [filterRefreshKey, setFilterRefreshKey] = useState(0) + const [showFilters, setShowFilters] = useState(true) const toggleTag = (tagId: string) => setSelectedTagIds((prev) => { @@ -64,20 +65,39 @@ export default function MoviesView({ libraryId }: Props) { setMovies((prev) => prev.filter((m) => m.id !== movieId)) } + const filtersActive = search !== '' || selectedTagIds.size > 0 + return ( -
-
- + <> +
+
-
+
+ {showFilters && ( +
+ +
+ )} +
{loading ? ( ) : error ? ( @@ -148,8 +168,9 @@ export default function MoviesView({ libraryId }: Props) { onDeleted={handleDeleted} /> )} +
-
+ ) } diff --git a/src/components/tv/TvView.tsx b/src/components/tv/TvView.tsx index 58b5c04..3639cfc 100644 --- a/src/components/tv/TvView.tsx +++ b/src/components/tv/TvView.tsx @@ -26,6 +26,7 @@ export default function TvView({ libraryId }: Props) { const [selectedTagIds, setSelectedTagIds] = useState>(new Set()) const [assignments, setAssignments] = useState>({}) const [filterRefreshKey, setFilterRefreshKey] = useState(0) + const [showFilters, setShowFilters] = useState(true) const [menuOpen, setMenuOpen] = useState(false) const [confirming, setConfirming] = useState(false) const [deleting, setDeleting] = useState(false) @@ -123,6 +124,8 @@ export default function TvView({ libraryId }: Props) { .catch(() => setDeleting(false)) } + const filtersActive = search !== '' || selectedTagIds.size > 0 + const filteredSeries = series.filter((s) => { if (search && !s.title.toLowerCase().includes(search.toLowerCase())) return false if (selectedTagIds.size > 0) { @@ -179,19 +182,36 @@ export default function TvView({ libraryId }: Props) {
{view === 'series' && ( -
-
- + <> +
+
-
+
+ {showFilters && ( +
+ +
+ )} +
{loading ? ( ) : error ? ( @@ -238,8 +258,9 @@ export default function TvView({ libraryId }: Props) { ))}
)} +
-
+ )} {view === 'seasons' && selectedSeries && (