fix(search): make the YouTube-search view its own history entry

The live-search results view had no browser-history entry of its own, so a
player opened over the results sat directly on the feed page entry. Pressing
Back (e.g. the mouse back button over the player) could pop past both the
player and the search in one step, bouncing from the search results to the
normal feed instead of just closing the player.

The search is now a feed sub-view that owns a history entry (history.state._yt):
entering a search pushes it, the popstate handler derives ytSearch from it, and
"Back to feed" pops it. Back now steps player -> search -> feed: the first Back
closes only the player (results stay), the second returns to the normal feed.
A reload drops any stale _yt so the first Back can't resurrect a gone search.
This commit is contained in:
npeter83 2026-06-29 23:03:25 +02:00
parent 1d6dfaf486
commit ff9b0601c3
2 changed files with 35 additions and 12 deletions

View file

@ -72,7 +72,8 @@ export default function Feed({
isDemo = false,
onOpenWizard,
ytSearch,
setYtSearch,
onYtSearch,
onExitYtSearch,
}: {
filters: FeedFilters;
setFilters: (f: FeedFilters) => void;
@ -80,10 +81,13 @@ export default function Feed({
canRead: boolean;
isDemo?: boolean;
onOpenWizard: () => void;
// Live YouTube search: the active search term (null = normal feed), and its setter so the
// empty-state CTA / "back to feed" can toggle it. Search affordances are hidden for demo.
// Live YouTube search: the active search term (null = normal feed). Entering a search and
// leaving it both step browser history (the search is a feed sub-view with its own history
// entry), so the empty-state CTA enters via onYtSearch and "back to feed" pops via
// onExitYtSearch. Search affordances are hidden for demo.
ytSearch: string | null;
setYtSearch: (q: string | null) => void;
onYtSearch: (q: string) => void;
onExitYtSearch: () => void;
}) {
const { t } = useTranslation();
const [overrides, setOverrides] = useState<Record<string, string>>({});
@ -292,7 +296,7 @@ export default function Feed({
// The search just ingested new catalog videos, so the normal feed (which was
// disabled and still holds its pre-search cache) is stale. Drop those caches so
// it re-fetches fresh on return instead of showing the old (often empty) result.
setYtSearch(null);
onExitYtSearch();
qc.removeQueries({ queryKey: ["feed"] });
qc.removeQueries({ queryKey: ["feed-count"] });
qc.removeQueries({ queryKey: ["facets"] });
@ -529,7 +533,7 @@ export default function Feed({
<p>{t("feed.noMatches")}</p>
{filters.q.trim() && !isDemo && (
<button
onClick={() => setYtSearch(filters.q.trim())}
onClick={() => onYtSearch(filters.q.trim())}
className="mt-4 inline-flex items-center gap-2 px-4 py-2 rounded-xl font-semibold bg-accent text-accent-fg hover:opacity-90 transition"
>
<Youtube className="w-4 h-4" />