diff --git a/src/pages/MyShows/MyShowsPage.tsx b/src/pages/MyShows/MyShowsPage.tsx
index f894e5d..7dd6e1b 100644
--- a/src/pages/MyShows/MyShowsPage.tsx
+++ b/src/pages/MyShows/MyShowsPage.tsx
@@ -178,11 +178,11 @@ export function MyShowsPage() {
downloadStore.removeDownload(id).catch(() => {});
},
"whitelist-toggle": () => {
- if (depth() < 1) return;
- const id = drilledShowId();
- if (!id) return;
const prefs = app.state().preferences;
if (prefs.autoDownloadScope !== "whitelist") return;
+ // depth 0: the focused show; depth ≥1: the drilled show.
+ const id = depth() >= 1 ? drilledShowId() : selectedShow()?.id;
+ if (!id) return;
const cur = prefs.autoDownloadWhitelist ?? [];
const next = cur.includes(id)
? cur.filter((x) => x !== id)
@@ -289,6 +289,11 @@ export function MyShowsPage() {
{(feed, index) => {
const lf = () => focusedShowIdx();
const ref = useScrollIntoView(() => index() === lf());
+ const wlScope =
+ app.state().preferences.autoDownloadScope === "whitelist";
+ const wlInList = (
+ app.state().preferences.autoDownloadWhitelist ?? []
+ ).includes(feed.id);
return (
({feed.episodes.length})
+
+
+ {wlInList ? "●" : "○"}
+
+
);
}}
@@ -410,7 +428,16 @@ export function MyShowsPage() {
{show().podcast.description?.slice(0, 400) ?? "No description."}
- enter/l: open · h: back · x: unsubscribe
+
+ enter/l: open · h: back · x: unsubscribe
+ {app.state().preferences.autoDownloadScope === "whitelist"
+ ? (app.state().preferences.autoDownloadWhitelist ??
+ []
+ ).includes(show().id)
+ ? " · w: un-whitelist"
+ : " · w: whitelist"
+ : ""}
+
)}
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
index 0203d68..5b30d40 100644
--- a/src/pages/Search/SearchPage.tsx
+++ b/src/pages/Search/SearchPage.tsx
@@ -280,6 +280,9 @@ function SearchPage() {
{(query, index) => {
const lf = () => focus(0);
const ref = useScrollIntoView(() => index() === lf());
+ // While the input is focused (typing), the list is not
+ // in focus: no bg, no accent fg, no `❯` on any entry.
+ const typing = () => inputActive();
return (
{
nav.setActivePane(DEPTH_CENTER_PANE);
nav.setDepthFocus(index(), 0);
@@ -297,10 +304,24 @@ function SearchPage() {
selectRecent(query);
}}
>
-
- {index() === lf() ? "❯" : " "}
+
+ {index() === lf() && !typing() ? "❯" : " "}
+
+
+ {query}
- {query}
);
}}
diff --git a/src/pages/Settings/PreferencesPanel.tsx b/src/pages/Settings/PreferencesPanel.tsx
index 968708a..a4e38a2 100644
--- a/src/pages/Settings/PreferencesPanel.tsx
+++ b/src/pages/Settings/PreferencesPanel.tsx
@@ -19,8 +19,10 @@ import { useAppStore } from "@/stores/app";
import { useFeedStore } from "@/stores/feed";
import { useTheme } from "@/context/ThemeContext";
import { useInputFocusNav } from "@/hooks/useInputFocusNav";
+import { useScrollIntoView } from "@/hooks/useScrollIntoView";
import {
NavMode,
+ useNavigation,
DEPTH_CENTER_PANE,
type PaneId,
} from "@/context/NavigationContext";
@@ -166,7 +168,7 @@ export function usePreferencesItems(): SettingItem[] {
kind: "select",
display: () => scopeLabel(prefs().autoDownloadScope),
help: () =>
- `Which shows auto-download applies to.\nAll: every subscribed show.\nNone: nothing.\nWhitelist: only the shows you add (in My Shows press ${"w"} on an episode; or open the Whitelist item below).\nType: select\nDefault: all\nCurrent: ${scopeLabel(prefs().autoDownloadScope)}\nCycle with j/k; Enter to apply.`,
+ `Which shows auto-download applies to.\nAll: every subscribed show.\nNone: nothing.\nWhitelist: only the shows you add (in My Shows press ${"w"} on the focused show; or open the Whitelist item below).\nType: select\nDefault: all\nCurrent: ${scopeLabel(prefs().autoDownloadScope)}\nCycle with j/k; Enter to apply.`,
cycle: (dir) => {
const idx = SCOPE_LABELS.findIndex(
(s) => s.value === prefs().autoDownloadScope,
@@ -299,6 +301,9 @@ const [wlQuery, setWlQuery] = createSignal("");
const [wlCursor, setWlCursor] = createSignal(0);
const [wlTyping, setWlTyping] = createSignal(true);
let wlEditorActive = false;
+// Indirection for refocusing the search input from the module-level nav.action
+// listener (which cannot call useNavigation — that needs the provider).
+let wlFocusInput: (() => void) | null = null;
function wlSuggestions(): Feed[] {
const q = wlQuery().trim().toLowerCase();
@@ -349,12 +354,17 @@ const wlOnAction = (data: {
case "open":
wlToggle(list[wlCursorClamped()].id);
break;
+ case "search":
+ // `s` while browsing re-enters typing mode (mirrors SearchPage).
+ wlFocusInput?.();
+ break;
}
};
on("nav.action", wlOnAction);
function WhitelistEditor() {
const { theme } = useTheme();
+ const nav = useNavigation();
const feedStore = useFeedStore();
const app = useAppStore();
@@ -363,8 +373,16 @@ function WhitelistEditor() {
onMount(() => {
wlEditorActive = true;
+ // Restore the last typing/browsing mode across the remounts that
+ // preference updates trigger. nav.inputFocused() drives the input's
+ // focused prop (deterministic Esc-to-blur, same as SearchPage), so
+ // keep the store in sync with the persisted module mode.
+ nav.setInputFocused(wlTyping());
+ wlFocusInput = () => nav.setInputFocused(true);
onCleanup(() => {
wlEditorActive = false;
+ nav.setInputFocused(false);
+ wlFocusInput = null;
});
});
@@ -372,6 +390,8 @@ function WhitelistEditor() {
const inputRef = (el: InputRenderable | null | undefined) => {
focusNavRef(el);
if (el) {
+ // Sync the persisted mode with real focus changes so remounts
+ // (e.g. after a toggle) restore the right state.
el.on(RenderableEvents.FOCUSED, () => setWlTyping(true));
el.on(RenderableEvents.BLURRED, () => setWlTyping(false));
}
@@ -388,7 +408,7 @@ function WhitelistEditor() {
ref={inputRef}
value={wlQuery()}
onInput={setWlQuery}
- focused={wlTyping()}
+ focused={nav.inputFocused()}
placeholder="Type to filter shows…"
width={30}
textColor={theme.text}
@@ -402,17 +422,30 @@ function WhitelistEditor() {
{(feed, index) => {
- const focused = index() === wlCursorClamped();
- const bg = () => (focused ? theme.primary : undefined);
- const fg = () => (focused ? theme.surface : theme.text);
+ // While the input is focused (typing), no row shows the
+ // accent highlight or `❯` — only the input is "in focus".
+ const focused = () =>
+ !nav.inputFocused() && index() === wlCursorClamped();
+ const ref = useScrollIntoView(focused);
+ const bg = () => (focused() ? theme.primary : undefined);
+ const fg = () => (focused() ? theme.surface : theme.text);
return (
{
+ nav.setActivePane(DEPTH_CENTER_PANE);
+ setWlCursor(index());
+ // Click toggles membership directly (works even
+ // while typing, where Space is input text).
+ wlToggle(feed.id);
+ }}
>
- {focused ? "❯" : " "}
+ {focused() ? "❯" : " "}
{inList(feed.id) ? "●" : "○"}
{feed.customName || feed.podcast.title}
@@ -422,7 +455,8 @@ function WhitelistEditor() {
}}
- Type to search · Esc to browse · j/k move · Space toggles · h back
+ Type to search · Esc to browse · j/k move · Space toggles · s to
+ type · h back
);