feat(filters): scope global feed filters in FeedFiltersProvider

Lift the feed's filter god-state (per-account persistence, the account-load
effect, share-link capture) out of App into a split-context provider mirroring
NavigationProvider. Sidebar/Header/NotificationsPanel read it via hooks instead
of prop-drilling; <Feed> keeps its filters prop since ChannelPage renders it with
its own channel-scoped state.
This commit is contained in:
2026-07-18 18:27:04 +02:00
parent 54a4b1b8aa
commit da143fd70d
6 changed files with 160 additions and 106 deletions
+4 -5
View File
@@ -1,20 +1,19 @@
import { type ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { Youtube } from "lucide-react";
import type { FeedFilters, Me } from "../lib/api";
import type { Me } from "../lib/api";
import { moduleLabelKey, moduleOrder, stepModule } from "../lib/modules";
import ModuleName from "./ModuleName";
import SearchBar from "./SearchBar";
import SyncStatus from "./SyncStatus";
import { useNavigation, useNavigationActions } from "./NavigationProvider";
import { useFeedFilters, useFeedFiltersActions } from "./FeedFiltersProvider";
// The floating top header: a row of glass pills over the content — a ModuleName pill (label +
// accent dot + back/forward arrows), the module's SearchBar where it has one, and the per-user
// sync chip at the right end.
export default function Header({
me,
filters,
setFilters,
plexQ,
setPlexQ,
channelsSearch,
@@ -25,8 +24,6 @@ export default function Header({
onGoToFullHistory,
}: {
me: Me;
filters: FeedFilters;
setFilters: (f: FeedFilters) => void;
// Plex has its own ephemeral search term (see App) — the box is shared UI, the state is not.
plexQ: string;
setPlexQ: (q: string) => void;
@@ -43,6 +40,8 @@ export default function Header({
const { t } = useTranslation();
const { page } = useNavigation();
const { setPage } = useNavigationActions();
const filters = useFeedFilters();
const { setFilters } = useFeedFiltersActions();
// The ◀/▶ arrows step cyclically through the user's available modules (derived from `me`, so
// it stays correct as modules are added/gated). Labels of every active module feed ModuleName's
// dynamic width so the pill is sized to the widest reachable title in the current language.