From f2b90449841373d9b0fdd70449f3e94c9dd0116d Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 26 Aug 2026 16:45:43 +0200 Subject: feat(video): add an All/Movies/Series filter to the toolbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A segmented control to the left of the search box, defaulting to "All". Applied before the text filter — a title match within a type nobody asked to see still isn't shown. Resets to "All" on group change, matching the text filter's own reset. --- .../src/meshbay_hub/static/video-app.js | 28 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/video-app.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/video-app.js b/packages/meshbay-hub/src/meshbay_hub/static/video-app.js index ce38b0e..dd120da 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/video-app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/video-app.js @@ -758,10 +758,14 @@ function VideoApp({ }) { const [mode, setMode] = useState(loadViewMode); const [filter, setFilter] = useState(''); + // Which of movies/shows to show at all — independent of the text filter + // below, and applied first: a title match within a type nobody asked to + // see is still not what "Movies only" means. + const [typeFilter, setTypeFilter] = useState('all'); const tmdbEnabled = tmdbConfig ? tmdbConfig.enabled : true; useEffect(() => { setMode(loadViewMode()); }, [groupId]); - useEffect(() => { setFilter(''); }, [groupId]); + useEffect(() => { setFilter(''); setTypeFilter('all'); }, [groupId]); const setModeAndSave = (m) => { setMode(m); saveViewMode(m); }; @@ -769,10 +773,10 @@ function VideoApp({ () => groupVideoEntries(entries, videoRoot), [entries, videoRoot]); const needle = filter.trim().toLowerCase(); - const filteredMovies = useMemo(() => (!needle ? movies : movies.filter( - (e) => (e.display_title || e.name).toLowerCase().includes(needle))), [movies, needle]); - const filteredShows = useMemo(() => (!needle ? shows : shows.filter( - (s) => s.title.toLowerCase().includes(needle))), [shows, needle]); + const filteredMovies = useMemo(() => (typeFilter === 'series' ? [] : !needle ? movies : movies.filter( + (e) => (e.display_title || e.name).toLowerCase().includes(needle))), [movies, needle, typeFilter]); + const filteredShows = useMemo(() => (typeFilter === 'movies' ? [] : !needle ? shows : shows.filter( + (s) => s.title.toLowerCase().includes(needle))), [shows, needle, typeFilter]); return html` ${(status === 'discovering' || status === 'connecting' || status === 'fetching') && html` @@ -794,6 +798,20 @@ function VideoApp({ onClick=${() => setModeAndSave('flat')}> ${t('video.mode_flat')} +
+ + + +