fix navigation flow
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
import { on, off } from "@/utils/event-bus";
|
||||
import type { KeybindActionName } from "@/context/KeybindContext";
|
||||
import { YaziPaneRow } from "@/components/YaziPaneRow";
|
||||
import { TabListPane } from "@/components/TabPanel";
|
||||
|
||||
export const DiscoverPaneCount = 1;
|
||||
|
||||
@@ -151,7 +152,7 @@ function DiscoverPage() {
|
||||
// Stable <Show> gate (not a ternary root swap) so the parent list
|
||||
// mounts/unmounts cleanly on depth change.
|
||||
const parentContent = () => (
|
||||
<Show when={depth() >= 1}>
|
||||
<Show when={depth() >= 1} fallback={<TabListPane muted />}>
|
||||
<For each={categories()}>
|
||||
{(cat, index) => (
|
||||
<box
|
||||
@@ -179,80 +180,29 @@ function DiscoverPage() {
|
||||
{/* depth 0: categories */}
|
||||
<Show when={depth() === 0}>
|
||||
<For each={categories()}>
|
||||
{(cat, index) => {
|
||||
const lf = focusedCatIdx();
|
||||
const selected = () => cat.id === discoverStore.selectedCategory();
|
||||
return (
|
||||
<box
|
||||
flexDirection="row"
|
||||
gap={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), lf, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 0);
|
||||
discoverStore.setSelectedCategory(cat.id);
|
||||
}}
|
||||
>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), lf, isActive())}>{cat.name}</text>
|
||||
<Show when={selected()}>
|
||||
<text fg={index() === lf ? theme.surface : theme.accent}>
|
||||
*
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</Show>
|
||||
{/* depth ≥1: results */}
|
||||
<Show when={depth() >= 1}>
|
||||
<Show
|
||||
when={podcasts().length > 0}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No podcasts found. :refresh</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={podcasts()}>
|
||||
{(podcast, index) => {
|
||||
const lf = focusedPodIdx();
|
||||
{(cat, index) => {
|
||||
const lf = focusedCatIdx();
|
||||
const selected = () => cat.id === discoverStore.selectedCategory();
|
||||
return (
|
||||
<box
|
||||
flexDirection="column"
|
||||
gap={0}
|
||||
flexDirection="row"
|
||||
gap={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), lf, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 1);
|
||||
nav.setDepthFocus(index(), 0);
|
||||
discoverStore.setSelectedCategory(cat.id);
|
||||
}}
|
||||
>
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{podcast.title}
|
||||
</text>
|
||||
<Show when={podcast.isSubscribed}>
|
||||
<text fg={index() === lf ? theme.surface : theme.success}>
|
||||
[+]
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
<Show when={podcast.author}>
|
||||
<text
|
||||
fg={index() === lf ? theme.surface : muted()}
|
||||
paddingLeft={2}
|
||||
>
|
||||
by {podcast.author}
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), lf, isActive())}>{cat.name}</text>
|
||||
<Show when={selected()}>
|
||||
<text fg={index() === lf ? theme.surface : theme.accent}>
|
||||
*
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
@@ -260,6 +210,57 @@ function DiscoverPage() {
|
||||
}}
|
||||
</For>
|
||||
</Show>
|
||||
{/* depth ≥1: results */}
|
||||
<Show when={depth() >= 1}>
|
||||
<Show
|
||||
when={podcasts().length > 0}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No podcasts found. :refresh</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={podcasts()}>
|
||||
{(podcast, index) => {
|
||||
const lf = focusedPodIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="column"
|
||||
gap={0}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), lf, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 1);
|
||||
}}
|
||||
>
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{podcast.title}
|
||||
</text>
|
||||
<Show when={podcast.isSubscribed}>
|
||||
<text fg={index() === lf ? theme.surface : theme.success}>
|
||||
[+]
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
<Show when={podcast.author}>
|
||||
<text
|
||||
fg={index() === lf ? theme.surface : muted()}
|
||||
paddingLeft={2}
|
||||
>
|
||||
by {podcast.author}
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</Show>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
@@ -316,8 +317,7 @@ function DiscoverPage() {
|
||||
</Show>
|
||||
<box height={1} />
|
||||
<text fg={theme.textSecondary}>
|
||||
{pod().description?.slice(0, 400) ??
|
||||
"No description available."}
|
||||
{pod().description?.slice(0, 400) ?? "No description available."}
|
||||
{(pod().description?.length ?? 0) > 400 ? "…" : ""}
|
||||
</text>
|
||||
<Show when={(pod().categories ?? []).length > 0}>
|
||||
|
||||
@@ -36,6 +36,7 @@ import type { Episode } from "@/types/episode";
|
||||
import type { Feed } from "@/types/feed";
|
||||
import { LoadingIndicator } from "@/components/LoadingIndicator";
|
||||
import { YaziPaneRow } from "@/components/YaziPaneRow";
|
||||
import { TabListPane } from "@/components/TabPanel";
|
||||
|
||||
export const FeedPaneCount = 1;
|
||||
|
||||
@@ -237,7 +238,7 @@ function FeedPage() {
|
||||
// Wrap in a stable <Show> (the sibling-Show pattern) so the parent list
|
||||
// mounts/unmounts cleanly on depth change instead of swapping roots.
|
||||
const parentContent = () => (
|
||||
<Show when={depth() >= 1}>
|
||||
<Show when={depth() >= 1} fallback={<TabListPane muted />}>
|
||||
<For each={feedList()}>
|
||||
{(item, index) => {
|
||||
const lf = nav.depthFocus(0);
|
||||
@@ -268,110 +269,110 @@ function FeedPage() {
|
||||
<Show when={depth() === 0}>
|
||||
<Show
|
||||
when={feedList().length > 1}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>
|
||||
No feeds. Subscribe from Discover/Search.
|
||||
</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={feedList()}>
|
||||
{(item, index) => {
|
||||
const fi = focusedFeedIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="row"
|
||||
gap={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), fi, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 0);
|
||||
}}
|
||||
>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{index() === fi ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{feedLabel(item)}
|
||||
</text>
|
||||
<text fg={index() === fi ? theme.surface : muted()}>
|
||||
({feedCount(item)})
|
||||
</text>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</Show>
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>
|
||||
No feeds. Subscribe from Discover/Search.
|
||||
</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={feedList()}>
|
||||
{(item, index) => {
|
||||
const fi = focusedFeedIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="row"
|
||||
gap={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), fi, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 0);
|
||||
}}
|
||||
>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{index() === fi ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{feedLabel(item)}
|
||||
</text>
|
||||
<text fg={index() === fi ? theme.surface : muted()}>
|
||||
({feedCount(item)})
|
||||
</text>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</Show>
|
||||
</Show>
|
||||
<Show when={depth() >= 1}>
|
||||
{/* depth ≥1: episodes */}
|
||||
<Show
|
||||
when={episodes().length > 0}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No episodes. :refresh</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={episodes()}>
|
||||
{(item, index) => {
|
||||
const fi = focusedEpIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="column"
|
||||
gap={0}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), fi, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 1);
|
||||
}}
|
||||
>
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{index() === fi ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{item.episode.episodeNumber
|
||||
? `#${item.episode.episodeNumber} `
|
||||
: ""}
|
||||
{item.episode.title}
|
||||
</text>
|
||||
</box>
|
||||
<box flexDirection="row" gap={2} paddingLeft={2}>
|
||||
<text fg={index() === fi ? theme.surface : theme.info}>
|
||||
{formatDate(item.episode.pubDate)}
|
||||
</text>
|
||||
<text fg={index() === fi ? theme.surface : muted()}>
|
||||
{formatDuration(item.episode.duration)}
|
||||
</text>
|
||||
<text fg={index() === fi ? theme.surface : muted()}>
|
||||
{item.feed.customName || item.feed.podcast.title}
|
||||
</text>
|
||||
<Show when={nav.isSelected(item.episode.id)}>
|
||||
<text fg={theme.warning}>●</text>
|
||||
</Show>
|
||||
<Show when={downloadLabel(item.episode.id)}>
|
||||
<text fg={downloadColor(item.episode.id)}>
|
||||
{downloadLabel(item.episode.id)}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No episodes. :refresh</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={episodes()}>
|
||||
{(item, index) => {
|
||||
const fi = focusedEpIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="column"
|
||||
gap={0}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), fi, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 1);
|
||||
}}
|
||||
>
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{index() === fi ? "❯" : " "}
|
||||
</text>
|
||||
</Show>
|
||||
<text fg={focusFg(index(), fi, isActive())}>
|
||||
{item.episode.episodeNumber
|
||||
? `#${item.episode.episodeNumber} `
|
||||
: ""}
|
||||
{item.episode.title}
|
||||
</text>
|
||||
</box>
|
||||
<box flexDirection="row" gap={2} paddingLeft={2}>
|
||||
<text fg={index() === fi ? theme.surface : theme.info}>
|
||||
{formatDate(item.episode.pubDate)}
|
||||
</text>
|
||||
<text fg={index() === fi ? theme.surface : muted()}>
|
||||
{formatDuration(item.episode.duration)}
|
||||
</text>
|
||||
<text fg={index() === fi ? theme.surface : muted()}>
|
||||
{item.feed.customName || item.feed.podcast.title}
|
||||
</text>
|
||||
<Show when={nav.isSelected(item.episode.id)}>
|
||||
<text fg={theme.warning}>●</text>
|
||||
</Show>
|
||||
<Show when={downloadLabel(item.episode.id)}>
|
||||
<text fg={downloadColor(item.episode.id)}>
|
||||
{downloadLabel(item.episode.id)}
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
<Show when={feedStore.isLoadingFeeds()}>
|
||||
<box paddingLeft={2} paddingTop={1}>
|
||||
<LoadingIndicator />
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
<Show when={feedStore.isLoadingFeeds()}>
|
||||
<box paddingLeft={2} paddingTop={1}>
|
||||
<LoadingIndicator />
|
||||
</box>
|
||||
</Show>
|
||||
</Show>
|
||||
</Show>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -439,12 +440,8 @@ function FeedPage() {
|
||||
</strong>
|
||||
</text>
|
||||
<box flexDirection="row" gap={2}>
|
||||
<text fg={theme.info}>
|
||||
{formatDate(it.episode.pubDate)}
|
||||
</text>
|
||||
<text fg={muted()}>
|
||||
{formatDuration(it.episode.duration)}
|
||||
</text>
|
||||
<text fg={theme.info}>{formatDate(it.episode.pubDate)}</text>
|
||||
<text fg={muted()}>{formatDuration(it.episode.duration)}</text>
|
||||
<Show when={downloadLabel(it.episode.id)}>
|
||||
<text fg={downloadColor(it.episode.id)}>
|
||||
{downloadLabel(it.episode.id)}
|
||||
|
||||
@@ -32,6 +32,7 @@ import type { Episode } from "@/types/episode";
|
||||
import type { Feed } from "@/types/feed";
|
||||
import { LoadingIndicator } from "@/components/LoadingIndicator";
|
||||
import { YaziPaneRow } from "@/components/YaziPaneRow";
|
||||
import { TabListPane } from "@/components/TabPanel";
|
||||
|
||||
export const MyShowsPaneCount = 1;
|
||||
|
||||
@@ -200,7 +201,7 @@ export function MyShowsPage() {
|
||||
// Stable <Show> gate (not a ternary root swap) so the parent list
|
||||
// mounts/unmounts cleanly on depth change.
|
||||
const parentContent = () => (
|
||||
<Show when={depth() >= 1}>
|
||||
<Show when={depth() >= 1} fallback={<TabListPane muted />}>
|
||||
<For each={shows()}>
|
||||
{(feed, index) => {
|
||||
const lf = nav.depthFocus(0);
|
||||
@@ -231,105 +232,105 @@ export function MyShowsPage() {
|
||||
<Show when={depth() === 0}>
|
||||
<Show
|
||||
when={shows().length > 0}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>
|
||||
No shows. Subscribe from Discover/Search.
|
||||
</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={shows()}>
|
||||
{(feed, index) => {
|
||||
const lf = focusedShowIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="row"
|
||||
gap={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), lf, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 0);
|
||||
}}
|
||||
>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{showTitle(feed)}
|
||||
</text>
|
||||
<text fg={index() === lf ? theme.surface : muted()}>
|
||||
({feed.episodes.length})
|
||||
</text>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</Show>
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>
|
||||
No shows. Subscribe from Discover/Search.
|
||||
</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={shows()}>
|
||||
{(feed, index) => {
|
||||
const lf = focusedShowIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="row"
|
||||
gap={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), lf, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 0);
|
||||
}}
|
||||
>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{showTitle(feed)}
|
||||
</text>
|
||||
<text fg={index() === lf ? theme.surface : muted()}>
|
||||
({feed.episodes.length})
|
||||
</text>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</Show>
|
||||
</Show>
|
||||
{/* depth ≥1: episodes */}
|
||||
<Show when={depth() >= 1}>
|
||||
<Show
|
||||
when={episodes().length > 0}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No episodes. :refresh</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={episodes()}>
|
||||
{(ep, index) => {
|
||||
const lf = focusedEpIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="column"
|
||||
gap={0}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), lf, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 1);
|
||||
}}
|
||||
>
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{ep.episodeNumber ? `#${ep.episodeNumber} ` : ""}
|
||||
{ep.title}
|
||||
</text>
|
||||
</box>
|
||||
<box flexDirection="row" gap={2} paddingLeft={2}>
|
||||
<text fg={index() === lf ? theme.surface : theme.info}>
|
||||
{formatDate(ep.pubDate)}
|
||||
</text>
|
||||
<text fg={index() === lf ? theme.surface : muted()}>
|
||||
{formatDuration(ep.duration)}
|
||||
</text>
|
||||
<Show when={nav.isSelected(ep.id)}>
|
||||
<text fg={theme.warning}>●</text>
|
||||
</Show>
|
||||
<Show when={downloadLabel(ep.id)}>
|
||||
<text fg={downloadColor(ep.id)}>
|
||||
{downloadLabel(ep.id)}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No episodes. :refresh</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<For each={episodes()}>
|
||||
{(ep, index) => {
|
||||
const lf = focusedEpIdx();
|
||||
return (
|
||||
<box
|
||||
flexDirection="column"
|
||||
gap={0}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={focusBg(index(), lf, isActive())}
|
||||
onMouseDown={() => {
|
||||
nav.setActivePane(DEPTH_CENTER_PANE);
|
||||
nav.setDepthFocus(index(), 1);
|
||||
}}
|
||||
>
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{index() === lf ? "❯" : " "}
|
||||
</text>
|
||||
</Show>
|
||||
<text fg={focusFg(index(), lf, isActive())}>
|
||||
{ep.episodeNumber ? `#${ep.episodeNumber} ` : ""}
|
||||
{ep.title}
|
||||
</text>
|
||||
</box>
|
||||
<box flexDirection="row" gap={2} paddingLeft={2}>
|
||||
<text fg={index() === lf ? theme.surface : theme.info}>
|
||||
{formatDate(ep.pubDate)}
|
||||
</text>
|
||||
<text fg={index() === lf ? theme.surface : muted()}>
|
||||
{formatDuration(ep.duration)}
|
||||
</text>
|
||||
<Show when={nav.isSelected(ep.id)}>
|
||||
<text fg={theme.warning}>●</text>
|
||||
</Show>
|
||||
<Show when={downloadLabel(ep.id)}>
|
||||
<text fg={downloadColor(ep.id)}>
|
||||
{downloadLabel(ep.id)}
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
<Show when={feedStore.isLoadingMore()}>
|
||||
<box paddingLeft={2} paddingTop={1}>
|
||||
<LoadingIndicator />
|
||||
</box>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
<Show when={feedStore.isLoadingMore()}>
|
||||
<box paddingLeft={2} paddingTop={1}>
|
||||
<LoadingIndicator />
|
||||
</box>
|
||||
</Show>
|
||||
</Show>
|
||||
</Show>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -357,8 +358,7 @@ export function MyShowsPage() {
|
||||
{show().episodes.length} episodes
|
||||
</text>
|
||||
<text fg={muted()}>
|
||||
{show().podcast.description?.slice(0, 400) ??
|
||||
"No description."}
|
||||
{show().podcast.description?.slice(0, 400) ?? "No description."}
|
||||
</text>
|
||||
<box height={1} />
|
||||
<text fg={muted()}>enter/l: open · h: back</text>
|
||||
@@ -397,8 +397,7 @@ export function MyShowsPage() {
|
||||
</Show>
|
||||
<box height={1} />
|
||||
<text fg={theme.textSecondary}>
|
||||
{ep().description?.slice(0, 400) ??
|
||||
"No description available."}
|
||||
{ep().description?.slice(0, 400) ?? "No description available."}
|
||||
{(ep().description?.length ?? 0) > 400 ? "…" : ""}
|
||||
</text>
|
||||
<box height={1} />
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* SearchPage — yazi-style 3-pane view.
|
||||
*
|
||||
* pane 0 (parent) — query input with recent-search history (clickable)
|
||||
* pane 1 (current) — search results list (navigate j/k)
|
||||
* pane 2 (preview) — detail of the focused search result
|
||||
* pane 1 (parent) — query input with recent-search history (clickable)
|
||||
* pane 2 (current) — search results list (navigate j/k)
|
||||
* pane 3 (preview) — detail of the focused search result
|
||||
*
|
||||
* The Shell resets activePane to CURRENT(1) on tab enter so the user lands on
|
||||
* the results pane. Swipe left (h) to pane 0 to type a query — the Shell
|
||||
* (pane 0 is the app's tab list.) The Shell resets activePane to CURRENT(2)
|
||||
* on tab enter so the user lands on the results pane. Swipe left (h) to pane
|
||||
* 1 to type a query — the Shell
|
||||
* router skips keys while `nav.inputFocused()` is true so the `<input>`
|
||||
* element captures typing natively. Press Enter (onSubmit) to search and
|
||||
* auto-swipe to the results pane.
|
||||
@@ -44,9 +45,9 @@ function SearchPage() {
|
||||
const muted = () => theme.muted || theme.text;
|
||||
const nav = useNavigation();
|
||||
|
||||
const INPUT = PaneSlot.PARENT; // 0
|
||||
const RESULTS = PaneSlot.CURRENT; // 1
|
||||
const DETAIL = PaneSlot.PREVIEW; // 2
|
||||
const INPUT = PaneSlot.PARENT; // 1 (input row)
|
||||
const RESULTS = PaneSlot.CURRENT; // 2 (results list)
|
||||
const DETAIL = PaneSlot.PREVIEW; // 3 (detail preview)
|
||||
|
||||
const results = () => searchStore.results();
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import { useVisualizerItems } from "./VisualizerSettings";
|
||||
import { useSyncItems, closeSyncEditor } from "./SyncPanel";
|
||||
import { useSourceItems } from "./SourceManager";
|
||||
import { YaziPaneRow } from "@/components/YaziPaneRow";
|
||||
import { TabListPane } from "@/components/TabPanel";
|
||||
|
||||
export const SettingsPaneCount = 1;
|
||||
|
||||
@@ -268,6 +269,10 @@ export function SettingsPage() {
|
||||
// root whose inner <Show> children swap instead.
|
||||
const parentContent = () => (
|
||||
<>
|
||||
<Show when={depth() === 0}>
|
||||
{/* app root: the tab list as the parent (muted) at the lowest depth */}
|
||||
<TabListPane muted />
|
||||
</Show>
|
||||
<Show when={depth() === 1}>
|
||||
{/* previous depth = sections list (read-only) */}
|
||||
<For each={SECTIONS}>
|
||||
|
||||
Reference in New Issue
Block a user