more indication
This commit is contained in:
@@ -43,13 +43,17 @@ export function DiscoverPage() {
|
|||||||
<box
|
<box
|
||||||
border
|
border
|
||||||
padding={1}
|
padding={1}
|
||||||
borderColor={theme.border}
|
borderColor={
|
||||||
|
nav.activeDepth() != DiscoverPagePaneType.CATEGORIES
|
||||||
|
? theme.border
|
||||||
|
: theme.accent
|
||||||
|
}
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
gap={1}
|
gap={1}
|
||||||
>
|
>
|
||||||
<text
|
<text
|
||||||
fg={
|
fg={
|
||||||
nav.activeDepth == DiscoverPagePaneType.CATEGORIES
|
nav.activeDepth() == DiscoverPagePaneType.CATEGORIES
|
||||||
? theme.accent
|
? theme.accent
|
||||||
: theme.text
|
: theme.text
|
||||||
}
|
}
|
||||||
@@ -76,61 +80,67 @@ export function DiscoverPage() {
|
|||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
flexGrow={1}
|
flexGrow={1}
|
||||||
border
|
border
|
||||||
borderColor={theme.border}
|
borderColor={
|
||||||
>
|
nav.activeDepth() == DiscoverPagePaneType.SHOWS
|
||||||
<box padding={1}>
|
? theme.accent
|
||||||
<SelectableText
|
: theme.border
|
||||||
selected={() => false}
|
}
|
||||||
primary={nav.activeDepth == DiscoverPagePaneType.SHOWS}
|
>
|
||||||
>
|
<box padding={1}>
|
||||||
Trending in{" "}
|
<SelectableText
|
||||||
{DISCOVER_CATEGORIES.find(
|
selected={() => false}
|
||||||
(c) => c.id === discoverStore.selectedCategory(),
|
primary={nav.activeDepth() == DiscoverPagePaneType.SHOWS}
|
||||||
)?.name ?? "All"}
|
>
|
||||||
</SelectableText>
|
Trending in{" "}
|
||||||
</box>
|
{DISCOVER_CATEGORIES.find(
|
||||||
<box flexDirection="column" height="100%">
|
(c) => c.id === discoverStore.selectedCategory(),
|
||||||
<Show
|
)?.name ?? "All"}
|
||||||
fallback={
|
</SelectableText>
|
||||||
<box padding={2}>
|
</box>
|
||||||
{discoverStore.filteredPodcasts().length !== 0 ? (
|
<box flexDirection="column" height="100%">
|
||||||
<text fg={theme.warning}>Loading trending shows...</text>
|
<Show
|
||||||
) : (
|
fallback={
|
||||||
<text fg={theme.textMuted}>
|
<box padding={2}>
|
||||||
No podcasts found in this category.
|
{discoverStore.filteredPodcasts().length !== 0 ? (
|
||||||
</text>
|
<text fg={theme.warning}>Loading trending shows...</text>
|
||||||
)}
|
) : (
|
||||||
</box>
|
<text fg={theme.textMuted}>
|
||||||
}
|
No podcasts found in this category.
|
||||||
when={
|
</text>
|
||||||
!discoverStore.isLoading() &&
|
|
||||||
discoverStore.filteredPodcasts().length === 0
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<scrollbox>
|
|
||||||
<box flexDirection="column">
|
|
||||||
<For each={discoverStore.filteredPodcasts()}>
|
|
||||||
{(podcast, index) => (
|
|
||||||
<PodcastCard
|
|
||||||
podcast={podcast}
|
|
||||||
selected={
|
|
||||||
index() === showIndex() &&
|
|
||||||
nav.activeDepth == DiscoverPagePaneType.SHOWS
|
|
||||||
}
|
|
||||||
onSelect={() => handleShowSelect(index())}
|
|
||||||
onSubscribe={() => handleSubscribe(podcast)}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</For>
|
</box>
|
||||||
</box>
|
}
|
||||||
</scrollbox>
|
when={
|
||||||
</Show>
|
!discoverStore.isLoading() &&
|
||||||
|
discoverStore.filteredPodcasts().length === 0
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<scrollbox
|
||||||
|
focused={nav.activeDepth() == DiscoverPagePaneType.SHOWS}
|
||||||
|
>
|
||||||
|
<box flexDirection="column">
|
||||||
|
<For each={discoverStore.filteredPodcasts()}>
|
||||||
|
{(podcast, index) => (
|
||||||
|
<PodcastCard
|
||||||
|
podcast={podcast}
|
||||||
|
selected={
|
||||||
|
index() === showIndex() &&
|
||||||
|
nav.activeDepth() == DiscoverPagePaneType.SHOWS
|
||||||
|
}
|
||||||
|
onSelect={() => handleShowSelect(index())}
|
||||||
|
onSubscribe={() => handleSubscribe(podcast)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</box>
|
||||||
|
</scrollbox>
|
||||||
|
</Show>
|
||||||
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
|
||||||
</box>
|
</box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,8 +129,14 @@ export function MyShowsPage() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<scrollbox
|
<scrollbox
|
||||||
|
border
|
||||||
height="100%"
|
height="100%"
|
||||||
focused={nav.activeDepth == MyShowsPaneType.SHOWS}
|
borderColor={
|
||||||
|
nav.activeDepth() == MyShowsPaneType.SHOWS
|
||||||
|
? theme.accent
|
||||||
|
: theme.border
|
||||||
|
}
|
||||||
|
focused={nav.activeDepth() == MyShowsPaneType.SHOWS}
|
||||||
>
|
>
|
||||||
<For each={shows()}>
|
<For each={shows()}>
|
||||||
{(feed, index) => (
|
{(feed, index) => (
|
||||||
@@ -171,26 +177,32 @@ export function MyShowsPage() {
|
|||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="column" height="100%">
|
<box flexDirection="column" height="100%">
|
||||||
<Show
|
|
||||||
when={selectedShow()}
|
|
||||||
fallback={
|
|
||||||
<box padding={1}>
|
|
||||||
<text fg={theme.muted}>Select a show</text>
|
|
||||||
</box>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Show
|
<Show
|
||||||
when={episodes().length > 0}
|
when={selectedShow()}
|
||||||
fallback={
|
fallback={
|
||||||
<box padding={1}>
|
<box padding={1}>
|
||||||
<text fg={theme.muted}>No episodes. Press [r] to refresh.</text>
|
<text fg={theme.muted}>Select a show</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<scrollbox
|
<Show
|
||||||
height="100%"
|
when={episodes().length > 0}
|
||||||
focused={nav.activeDepth == MyShowsPaneType.EPISODES}
|
fallback={
|
||||||
|
<box padding={1}>
|
||||||
|
<text fg={theme.muted}>No episodes. Press [r] to refresh.</text>
|
||||||
|
</box>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
|
<scrollbox
|
||||||
|
border
|
||||||
|
height="100%"
|
||||||
|
borderColor={
|
||||||
|
nav.activeDepth() == MyShowsPaneType.EPISODES
|
||||||
|
? theme.accent
|
||||||
|
: theme.border
|
||||||
|
}
|
||||||
|
focused={nav.activeDepth() == MyShowsPaneType.EPISODES}
|
||||||
|
>
|
||||||
<For each={episodes()}>
|
<For each={episodes()}>
|
||||||
{(episode, index) => (
|
{(episode, index) => (
|
||||||
<box
|
<box
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { RealtimeWaveform } from "./RealtimeWaveform";
|
|||||||
import { useAudio } from "@/hooks/useAudio";
|
import { useAudio } from "@/hooks/useAudio";
|
||||||
import { useAppStore } from "@/stores/app";
|
import { useAppStore } from "@/stores/app";
|
||||||
import { useTheme } from "@/context/ThemeContext";
|
import { useTheme } from "@/context/ThemeContext";
|
||||||
|
import { useNavigation } from "@/context/NavigationContext";
|
||||||
|
|
||||||
enum PlayerPaneType {
|
enum PlayerPaneType {
|
||||||
PLAYER = 1,
|
PLAYER = 1,
|
||||||
@@ -12,6 +13,7 @@ export const PlayerPaneCount = 1;
|
|||||||
export function PlayerPage() {
|
export function PlayerPage() {
|
||||||
const audio = useAudio();
|
const audio = useAudio();
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
const nav = useNavigation();
|
||||||
|
|
||||||
const progressPercent = () => {
|
const progressPercent = () => {
|
||||||
const d = audio.duration();
|
const d = audio.duration();
|
||||||
@@ -41,7 +43,7 @@ export function PlayerPage() {
|
|||||||
|
|
||||||
<box
|
<box
|
||||||
border
|
border
|
||||||
borderColor={theme.border}
|
borderColor={nav.activeDepth() == PlayerPaneType.PLAYER ? theme.accent : theme.border}
|
||||||
padding={1}
|
padding={1}
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
gap={1}
|
gap={1}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function SearchPage() {
|
|||||||
setInputValue(value);
|
setInputValue(value);
|
||||||
}}
|
}}
|
||||||
placeholder="Enter podcast name, topic, or author..."
|
placeholder="Enter podcast name, topic, or author..."
|
||||||
focused={nav.activeDepth === SearchPaneType.INPUT}
|
focused={nav.activeDepth() === SearchPaneType.INPUT}
|
||||||
width={50}
|
width={50}
|
||||||
/>
|
/>
|
||||||
<box
|
<box
|
||||||
@@ -92,76 +92,80 @@ export function SearchPage() {
|
|||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
|
|
||||||
{/* Main Content - Results or History */}
|
{/* Main Content - Results or History */}
|
||||||
<box flexDirection="row" height="100%" gap={2}>
|
<box flexDirection="row" height="100%" gap={2}>
|
||||||
{/* Results Panel */}
|
{/* Results Panel */}
|
||||||
<box
|
<box
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
flexGrow={1}
|
flexGrow={1}
|
||||||
border
|
border
|
||||||
borderColor={theme.border}
|
borderColor={
|
||||||
>
|
nav.activeDepth() === SearchPaneType.RESULTS
|
||||||
<box padding={1}>
|
? theme.accent
|
||||||
<text
|
: theme.border
|
||||||
fg={
|
|
||||||
nav.activeDepth === SearchPaneType.RESULTS
|
|
||||||
? theme.primary
|
|
||||||
: theme.muted
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Results ({searchStore.results().length})
|
|
||||||
</text>
|
|
||||||
</box>
|
|
||||||
<Show
|
|
||||||
when={searchStore.results().length > 0}
|
|
||||||
fallback={
|
|
||||||
<box padding={2}>
|
|
||||||
<text fg={theme.muted}>
|
|
||||||
{searchStore.query()
|
|
||||||
? "No results found"
|
|
||||||
: "Enter a search term to find podcasts"}
|
|
||||||
</text>
|
|
||||||
</box>
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SearchResults
|
<box padding={1}>
|
||||||
results={searchStore.results()}
|
|
||||||
selectedIndex={resultIndex()}
|
|
||||||
focused={nav.activeDepth === SearchPaneType.RESULTS}
|
|
||||||
onSelect={handleResultSelect}
|
|
||||||
onChange={setResultIndex}
|
|
||||||
isSearching={searchStore.isSearching()}
|
|
||||||
error={searchStore.error()}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
</box>
|
|
||||||
|
|
||||||
{/* History Sidebar */}
|
|
||||||
<box width={30} border borderColor={theme.border}>
|
|
||||||
<box padding={1} flexDirection="column">
|
|
||||||
<box paddingBottom={1}>
|
|
||||||
<text
|
<text
|
||||||
fg={
|
fg={
|
||||||
nav.activeDepth === SearchPaneType.HISTORY
|
nav.activeDepth() === SearchPaneType.RESULTS
|
||||||
? theme.primary
|
? theme.primary
|
||||||
: theme.muted
|
: theme.muted
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
History
|
Results ({searchStore.results().length})
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<SearchHistory
|
<Show
|
||||||
history={searchStore.history()}
|
when={searchStore.results().length > 0}
|
||||||
selectedIndex={historyIndex()}
|
fallback={
|
||||||
focused={nav.activeDepth === SearchPaneType.HISTORY}
|
<box padding={2}>
|
||||||
onSelect={handleHistorySelect}
|
<text fg={theme.muted}>
|
||||||
onRemove={searchStore.removeFromHistory}
|
{searchStore.query()
|
||||||
onClear={searchStore.clearHistory}
|
? "No results found"
|
||||||
onChange={setHistoryIndex}
|
: "Enter a search term to find podcasts"}
|
||||||
/>
|
</text>
|
||||||
|
</box>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SearchResults
|
||||||
|
results={searchStore.results()}
|
||||||
|
selectedIndex={resultIndex()}
|
||||||
|
focused={nav.activeDepth() === SearchPaneType.RESULTS}
|
||||||
|
onSelect={handleResultSelect}
|
||||||
|
onChange={setResultIndex}
|
||||||
|
isSearching={searchStore.isSearching()}
|
||||||
|
error={searchStore.error()}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</box>
|
||||||
|
|
||||||
|
{/* History Sidebar */}
|
||||||
|
<box width={30} border borderColor={theme.border}>
|
||||||
|
<box padding={1} flexDirection="column">
|
||||||
|
<box paddingBottom={1}>
|
||||||
|
<text
|
||||||
|
fg={
|
||||||
|
nav.activeDepth() === SearchPaneType.HISTORY
|
||||||
|
? theme.primary
|
||||||
|
: theme.muted
|
||||||
|
}
|
||||||
|
>
|
||||||
|
History
|
||||||
|
</text>
|
||||||
|
</box>
|
||||||
|
<SearchHistory
|
||||||
|
history={searchStore.history()}
|
||||||
|
selectedIndex={historyIndex()}
|
||||||
|
focused={nav.activeDepth() === SearchPaneType.HISTORY}
|
||||||
|
onSelect={handleHistorySelect}
|
||||||
|
onRemove={searchStore.removeFromHistory}
|
||||||
|
onClear={searchStore.clearHistory}
|
||||||
|
onChange={setHistoryIndex}
|
||||||
|
/>
|
||||||
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
|
||||||
</box>
|
</box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ export function SettingsPage() {
|
|||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const nav = useNavigation();
|
const nav = useNavigation();
|
||||||
|
|
||||||
|
// Helper function to check if a depth is active
|
||||||
|
const isActive = (depth: SettingsPaneType): boolean => {
|
||||||
|
return nav.activeDepth() === depth;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box flexDirection="column" gap={1} height="100%" width="100%">
|
<box flexDirection="column" gap={1} height="100%" width="100%">
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
@@ -56,23 +61,23 @@ export function SettingsPage() {
|
|||||||
|
|
||||||
<box
|
<box
|
||||||
border
|
border
|
||||||
borderColor={theme.border}
|
borderColor={isActive(SettingsPaneType.SYNC) || isActive(SettingsPaneType.SOURCES) || isActive(SettingsPaneType.PREFERENCES) || isActive(SettingsPaneType.VISUALIZER) || isActive(SettingsPaneType.ACCOUNT) ? theme.accent : theme.border}
|
||||||
flexGrow={1}
|
flexGrow={1}
|
||||||
padding={1}
|
padding={1}
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
gap={1}
|
gap={1}
|
||||||
>
|
>
|
||||||
{nav.activeDepth === SettingsPaneType.SYNC && <SyncPanel />}
|
{isActive(SettingsPaneType.SYNC) && <SyncPanel />}
|
||||||
{nav.activeDepth === SettingsPaneType.SOURCES && (
|
{isActive(SettingsPaneType.SOURCES) && (
|
||||||
<SourceManager focused />
|
<SourceManager focused />
|
||||||
)}
|
)}
|
||||||
{nav.activeDepth === SettingsPaneType.PREFERENCES && (
|
{isActive(SettingsPaneType.PREFERENCES) && (
|
||||||
<PreferencesPanel />
|
<PreferencesPanel />
|
||||||
)}
|
)}
|
||||||
{nav.activeDepth === SettingsPaneType.VISUALIZER && (
|
{isActive(SettingsPaneType.VISUALIZER) && (
|
||||||
<VisualizerSettings />
|
<VisualizerSettings />
|
||||||
)}
|
)}
|
||||||
{nav.activeDepth === SettingsPaneType.ACCOUNT && (
|
{isActive(SettingsPaneType.ACCOUNT) && (
|
||||||
<box flexDirection="column" gap={1}>
|
<box flexDirection="column" gap={1}>
|
||||||
<text fg={theme.textMuted}>Account</text>
|
<text fg={theme.textMuted}>Account</text>
|
||||||
</box>
|
</box>
|
||||||
|
|||||||
Reference in New Issue
Block a user