Merge: unify filter reset — Source/scope count + clear, search ✕

This commit is contained in:
npeter83 2026-07-01 04:22:39 +02:00
commit 8e5066f1d3
5 changed files with 31 additions and 5 deletions

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Library, Search, User, Youtube } from "lucide-react"; import { Library, Search, User, X, Youtube } from "lucide-react";
import type { FeedFilters, Me } from "../lib/api"; import type { FeedFilters, Me } from "../lib/api";
import type { Page } from "../lib/urlState"; import type { Page } from "../lib/urlState";
import SyncStatus from "./SyncStatus"; import SyncStatus from "./SyncStatus";
@ -81,8 +81,18 @@ export default function Header({
if (e.key === "Enter" && trimmedQ && canSearchYt) onYtSearch(trimmedQ); if (e.key === "Enter" && trimmedQ && canSearchYt) onYtSearch(trimmedQ);
}} }}
placeholder={t("header.searchPlaceholder")} placeholder={t("header.searchPlaceholder")}
className="w-full bg-card border border-border rounded-full pl-9 pr-4 py-2 text-sm outline-none focus:border-accent" className="w-full bg-card border border-border rounded-full pl-9 pr-9 py-2 text-sm outline-none focus:border-accent"
/> />
{filters.q && (
<button
onClick={() => setFilters({ ...filters, q: "" })}
title={t("header.clearSearch")}
aria-label={t("header.clearSearch")}
className="absolute right-2.5 top-1/2 -translate-y-1/2 p-0.5 rounded-full text-muted hover:text-fg hover:bg-border/60 transition"
>
<X className="w-4 h-4" />
</button>
)}
</div> </div>
{trimmedQ && canSearchYt && ( {trimmedQ && canSearchYt && (
<button <button

View file

@ -207,13 +207,23 @@ export default function Sidebar({
const dateActive = !!filters.maxAgeDays || !!filters.dateFrom || !!filters.dateTo; const dateActive = !!filters.maxAgeDays || !!filters.dateFrom || !!filters.dateTo;
const contentChanged = const contentChanged =
!filters.includeNormal || filters.includeShorts || filters.includeLive; !filters.includeNormal || filters.includeShorts || filters.includeLive;
// Library (vs the default "my"/Mine) and a non-default provenance Source both narrow the feed,
// so they count as active filters too (Source only applies in Library scope). The header search
// `q` deliberately stays out — it has its own clear (✕) in the search box and isn't reset here.
const scopeActive = filters.scope === "all";
const sourceActive =
filters.scope === "all" && !!filters.librarySource && filters.librarySource !== "organic";
const activeCount = const activeCount =
filters.tags.length + filters.tags.length +
(filters.show !== "unwatched" ? 1 : 0) + (filters.show !== "unwatched" ? 1 : 0) +
(filters.sort !== "newest" ? 1 : 0) + // "relevance" is auto-applied while searching (no manual dropdown option), so it's a search
// artifact, not a user-chosen sort filter — don't let typing a query inflate the count.
(filters.sort !== "newest" && filters.sort !== "relevance" ? 1 : 0) +
(contentChanged ? 1 : 0) + (contentChanged ? 1 : 0) +
(filters.channelId ? 1 : 0) + (filters.channelId ? 1 : 0) +
(dateActive ? 1 : 0); (dateActive ? 1 : 0) +
(scopeActive ? 1 : 0) +
(sourceActive ? 1 : 0);
const active = activeCount > 0; const active = activeCount > 0;
async function shareView() { async function shareView() {
@ -227,7 +237,10 @@ export default function Sidebar({
function clearAll() { function clearAll() {
setCustomDates(false); setCustomDates(false);
setFilters({ ...DEFAULT_SIDEBAR_FILTERS, q: filters.q, scope: filters.scope }); // Reset every filter dimension to its default — including scope back to "my" (Mine) and the
// provenance Source (dropped with the rest, so it falls back to "organic"). The search `q` is
// intentionally preserved (it has its own ✕ in the search box).
setFilters({ ...DEFAULT_SIDEBAR_FILTERS, q: filters.q, scope: "my" });
} }
const available: Record<WidgetId, boolean> = { const available: Record<WidgetId, boolean> = {

View file

@ -1,6 +1,7 @@
{ {
"feed": "Feed", "feed": "Feed",
"searchPlaceholder": "Deine Abos durchsuchen…", "searchPlaceholder": "Deine Abos durchsuchen…",
"clearSearch": "Suche löschen",
"searchYoutube": "Auf YouTube suchen", "searchYoutube": "Auf YouTube suchen",
"searchYoutubeTip": "Live auf YouTube nach diesem Begriff suchen (verbraucht gemeinsames API-Kontingent). Du kannst auch Enter drücken.", "searchYoutubeTip": "Live auf YouTube nach diesem Begriff suchen (verbraucht gemeinsames API-Kontingent). Du kannst auch Enter drücken.",
"channelManager": "Kanalverwaltung", "channelManager": "Kanalverwaltung",

View file

@ -1,6 +1,7 @@
{ {
"feed": "Feed", "feed": "Feed",
"searchPlaceholder": "Search your subscriptions…", "searchPlaceholder": "Search your subscriptions…",
"clearSearch": "Clear search",
"searchYoutube": "Search YouTube", "searchYoutube": "Search YouTube",
"searchYoutubeTip": "Search live on YouTube for this term (uses shared API quota). You can also press Enter.", "searchYoutubeTip": "Search live on YouTube for this term (uses shared API quota). You can also press Enter.",
"channelManager": "Channel manager", "channelManager": "Channel manager",

View file

@ -1,6 +1,7 @@
{ {
"feed": "Hírfolyam", "feed": "Hírfolyam",
"searchPlaceholder": "Keresés a feliratkozásaid között…", "searchPlaceholder": "Keresés a feliratkozásaid között…",
"clearSearch": "Keresés törlése",
"searchYoutube": "Keresés a YouTube-on", "searchYoutube": "Keresés a YouTube-on",
"searchYoutubeTip": "Élő keresés a YouTube-on erre a kifejezésre (a közös API-kvótát fogyasztja). Entert is nyomhatsz.", "searchYoutubeTip": "Élő keresés a YouTube-on erre a kifejezésre (a közös API-kvótát fogyasztja). Entert is nyomhatsz.",
"channelManager": "Csatornakezelő", "channelManager": "Csatornakezelő",