diff --git a/src/App.tsx b/src/App.tsx
index 985478b..6494ea0 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,15 +1,9 @@
import { createSignal, createMemo, ErrorBoundary, Accessor } from "solid-js";
import { useSelectionHandler } from "@opentui/solid";
import { TabNavigation } from "./components/TabNavigation";
-import { FeedPage } from "@/tabs/Feed/FeedPage";
-import { MyShowsPage } from "@/tabs/MyShows/MyShowsPage";
-import { LoginScreen } from "@/tabs/Settings/LoginScreen";
+
import { CodeValidation } from "@/components/CodeValidation";
-import { OAuthPlaceholder } from "@/tabs/Settings/OAuthPlaceholder";
-import { SyncProfile } from "@/tabs/Settings/SyncProfile";
-import { SearchPage } from "@/tabs/Search/SearchPage";
-import { DiscoverPage } from "@/tabs/Discover/DiscoverPage";
-import { SettingsScreen } from "@/tabs/Settings/SettingsScreen";
+
import { useAuthStore } from "@/stores/auth";
import { useFeedStore } from "@/stores/feed";
import { useAudio } from "@/hooks/useAudio";
@@ -21,8 +15,7 @@ import { useToast } from "@/ui/toast";
import { useRenderer } from "@opentui/solid";
import type { AuthScreen } from "@/types/auth";
import type { Episode } from "@/types/episode";
-import { DIRECTION } from "./types/navigation";
-import { LayerGraph, TABS } from "./utils/navigation";
+import { DIRECTION, LayerGraph, TABS } from "./utils/navigation";
import { useTheme } from "./context/ThemeContext";
export interface PageProps {
@@ -119,6 +112,7 @@ export function App() {
>
{LayerGraph[activeTab()]({ depth: activeDepth })}
+ {/**TODO: Contextual controls based on tab/depth**/}
);
diff --git a/src/pages/Feed/FeedPage.tsx b/src/pages/Feed/FeedPage.tsx
index b6e2c9e..255b037 100644
--- a/src/pages/Feed/FeedPage.tsx
+++ b/src/pages/Feed/FeedPage.tsx
@@ -11,6 +11,9 @@ import type { Feed } from "@/types/feed";
import { useTheme } from "@/context/ThemeContext";
import { PageProps } from "@/App";
+enum FeedPaneType {
+ FEED = 1,
+}
export const FeedPaneCount = 1;
export function FeedPage(props: PageProps) {
@@ -60,7 +63,7 @@ export function FeedPage(props: PageProps) {
}
>
{/**TODO: figure out wtf to do here **/}
-
+
{(item, index) => (
("shows");
const [showIndex, setShowIndex] = createSignal(0);
const [episodeIndex, setEpisodeIndex] = createSignal(0);
const [isRefreshing, setIsRefreshing] = createSignal(false);
@@ -128,8 +127,8 @@ export function MyShowsPage(props: PageProps) {
setEpisodeIndex(0);
};
- return {
- showsPanel: () => (
+ return (
+
Refreshing...
@@ -144,7 +143,10 @@ export function MyShowsPage(props: PageProps) {
}
>
-
+
{(feed, index) => (
- ),
-
- episodesPanel: () => (
{(episode, index) => (
@@ -252,9 +251,6 @@ export function MyShowsPage(props: PageProps) {
- ),
-
- focusPane,
- selectedShow,
- };
+
+ );
}
diff --git a/src/pages/Player/PlayerPage.tsx b/src/pages/Player/PlayerPage.tsx
index 5815faa..96b9d95 100644
--- a/src/pages/Player/PlayerPage.tsx
+++ b/src/pages/Player/PlayerPage.tsx
@@ -1,9 +1,15 @@
+import { PageProps } from "@/App";
import { PlaybackControls } from "./PlaybackControls";
import { RealtimeWaveform } from "./RealtimeWaveform";
import { useAudio } from "@/hooks/useAudio";
import { useAppStore } from "@/stores/app";
-export function PlayerPage() {
+enum PlayerPaneType {
+ PLAYER = 1,
+}
+export const PlayerPaneCount = 1;
+
+export function PlayerPage(props: PageProps) {
const audio = useAudio();
const progressPercent = () => {
@@ -63,11 +69,6 @@ export function PlayerPage() {
onSpeedChange={(s: number) => audio.setSpeed(s)}
onVolumeChange={(v: number) => audio.setVolume(v)}
/>
-
-
- Space play/pause | Left/Right seek 10s | Up/Down volume | S speed | Esc
- back
-
);
}
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
index eeeecd7..f5d0efd 100644
--- a/src/pages/Search/SearchPage.tsx
+++ b/src/pages/Search/SearchPage.tsx
@@ -8,35 +8,35 @@ import { useSearchStore } from "@/stores/search";
import { SearchResults } from "./SearchResults";
import { SearchHistory } from "./SearchHistory";
import type { SearchResult } from "@/types/source";
+import { PageProps } from "@/App";
+import { MyShowsPage } from "../MyShows/MyShowsPage";
-type SearchPageProps = {
- focused: boolean;
- onSubscribe?: (result: SearchResult) => void;
- onInputFocusChange?: (focused: boolean) => void;
- onExit?: () => void;
-};
+enum SearchPaneType {
+ INPUT = 1,
+ RESULTS = 2,
+ HISTORY = 3,
+}
+export const SearchPaneCount = 3;
-type FocusArea = "input" | "results" | "history";
-
-export function SearchPage(props: SearchPageProps) {
+export function SearchPage(props: PageProps) {
const searchStore = useSearchStore();
- const [focusArea, setFocusArea] = createSignal("input");
const [inputValue, setInputValue] = createSignal("");
const [resultIndex, setResultIndex] = createSignal(0);
const [historyIndex, setHistoryIndex] = createSignal(0);
// Keep parent informed about input focus state
- createEffect(() => {
- const isInputFocused = props.focused && focusArea() === "input";
- props.onInputFocusChange?.(isInputFocused);
- });
+ // TODO: have a global input focused prop in useKeyboard hook
+ //createEffect(() => {
+ //const isInputFocused = props.focused && focusArea() === "input";
+ //props.onInputFocusChange?.(isInputFocused);
+ //});
const handleSearch = async () => {
const query = inputValue().trim();
if (query) {
await searchStore.search(query);
if (searchStore.results().length > 0) {
- setFocusArea("results");
+ //setFocusArea("results"); //TODO: move level
setResultIndex(0);
}
}
@@ -46,120 +46,16 @@ export function SearchPage(props: SearchPageProps) {
setInputValue(query);
await searchStore.search(query);
if (searchStore.results().length > 0) {
- setFocusArea("results");
+ //setFocusArea("results"); //TODO: move level
setResultIndex(0);
}
};
const handleResultSelect = (result: SearchResult) => {
- props.onSubscribe?.(result);
+ //props.onSubscribe?.(result);
searchStore.markSubscribed(result.podcast.id);
};
- // Keyboard navigation
- useKeyboard((key) => {
- if (!props.focused) return;
-
- const area = focusArea();
-
- // Enter to search from input
- if (key.name === "return" && area === "input") {
- handleSearch();
- return;
- }
-
- // Tab to cycle focus areas
- if (key.name === "tab" && !key.shift) {
- if (area === "input") {
- if (searchStore.results().length > 0) {
- setFocusArea("results");
- } else if (searchStore.history().length > 0) {
- setFocusArea("history");
- }
- } else if (area === "results") {
- if (searchStore.history().length > 0) {
- setFocusArea("history");
- } else {
- setFocusArea("input");
- }
- } else {
- setFocusArea("input");
- }
- return;
- }
-
- if (key.name === "tab" && key.shift) {
- if (area === "input") {
- if (searchStore.history().length > 0) {
- setFocusArea("history");
- } else if (searchStore.results().length > 0) {
- setFocusArea("results");
- }
- } else if (area === "history") {
- if (searchStore.results().length > 0) {
- setFocusArea("results");
- } else {
- setFocusArea("input");
- }
- } else {
- setFocusArea("input");
- }
- return;
- }
-
- // Up/Down for results and history
- if (area === "results") {
- const results = searchStore.results();
- if (key.name === "down" || key.name === "j") {
- setResultIndex((i) => Math.min(i + 1, results.length - 1));
- return;
- }
- if (key.name === "up" || key.name === "k") {
- setResultIndex((i) => Math.max(i - 1, 0));
- return;
- }
- if (key.name === "return" || key.name === "enter") {
- const result = results[resultIndex()];
- if (result) handleResultSelect(result);
- return;
- }
- }
-
- if (area === "history") {
- const history = searchStore.history();
- if (key.name === "down" || key.name === "j") {
- setHistoryIndex((i) => Math.min(i + 1, history.length - 1));
- return;
- }
- if (key.name === "up" || key.name === "k") {
- setHistoryIndex((i) => Math.max(i - 1, 0));
- return;
- }
- if (key.name === "return" || key.name === "enter") {
- const query = history[historyIndex()];
- if (query) handleHistorySelect(query);
- return;
- }
- }
-
- // Escape goes back to input or up one level
- if (key.name === "escape") {
- if (area === "input") {
- props.onExit?.();
- } else {
- setFocusArea("input");
- key.stopPropagation();
- }
- return;
- }
-
- // "/" focuses search input
- if (key.name === "/" && area !== "input") {
- setFocusArea("input");
- return;
- }
- });
-
return (
{/* Search Header */}
@@ -177,7 +73,7 @@ export function SearchPage(props: SearchPageProps) {
setInputValue(value);
}}
placeholder="Enter podcast name, topic, or author..."
- focused={props.focused && focusArea() === "input"}
+ focused={props.depth() === SearchPaneType.INPUT}
width={50}
/>
-
+
Results ({searchStore.results().length})
@@ -224,7 +122,7 @@ export function SearchPage(props: SearchPageProps) {
-
+
History
-
- {/* Footer Hints */}
-
- [Tab] Switch focus
- [/] Focus search
- [Enter] Select
- [Esc] Up
-
);
}
diff --git a/src/pages/Settings/SettingsPage.tsx b/src/pages/Settings/SettingsPage.tsx
index d57160f..3d5240b 100644
--- a/src/pages/Settings/SettingsPage.tsx
+++ b/src/pages/Settings/SettingsPage.tsx
@@ -5,65 +5,33 @@ import { useTheme } from "@/context/ThemeContext";
import { PreferencesPanel } from "./PreferencesPanel";
import { SyncPanel } from "./SyncPanel";
import { VisualizerSettings } from "./VisualizerSettings";
+import { PageProps } from "@/App";
-type SettingsScreenProps = {
- accountLabel: string;
- accountStatus: "signed-in" | "signed-out";
- onOpenAccount?: () => void;
- onExit?: () => void;
-};
+enum SettingsPaneType {
+ SYNC = 1,
+ SOURCES = 2,
+ PREFERENCES = 3,
+ VISUALIZER = 4,
+ ACCOUNT = 5,
+}
+export const SettingsPaneCount = 5;
-type SectionId = "sync" | "sources" | "preferences" | "visualizer" | "account";
-
-const SECTIONS: Array<{ id: SectionId; label: string }> = [
- { id: "sync", label: "Sync" },
- { id: "sources", label: "Sources" },
- { id: "preferences", label: "Preferences" },
- { id: "visualizer", label: "Visualizer" },
- { id: "account", label: "Account" },
+const SECTIONS: Array<{ id: SettingsPaneType; label: string }> = [
+ { id: SettingsPaneType.SYNC, label: "Sync" },
+ { id: SettingsPaneType.SOURCES, label: "Sources" },
+ { id: SettingsPaneType.PREFERENCES, label: "Preferences" },
+ { id: SettingsPaneType.VISUALIZER, label: "Visualizer" },
+ { id: SettingsPaneType.ACCOUNT, label: "Account" },
];
-export function SettingsPage(props: SettingsScreenProps) {
+export function SettingsPage(props: PageProps) {
const { theme } = useTheme();
- const [activeSection, setActiveSection] = createSignal("sync");
-
- useKeyboard((key) => {
- if (key.name === "escape") {
- props.onExit?.();
- return;
- }
-
- if (key.name === "tab") {
- const idx = SECTIONS.findIndex((s) => s.id === activeSection());
- const next = key.shift
- ? (idx - 1 + SECTIONS.length) % SECTIONS.length
- : (idx + 1) % SECTIONS.length;
- setActiveSection(SECTIONS[next].id);
- return;
- }
-
- if (key.name === "1") setActiveSection("sync");
- if (key.name === "2") setActiveSection("sources");
- if (key.name === "3") setActiveSection("preferences");
- if (key.name === "4") setActiveSection("visualizer");
- if (key.name === "5") setActiveSection("account");
- });
+ const [activeSection, setActiveSection] = createSignal(
+ SettingsPaneType.SYNC,
+ );
return (
-
-
- Settings
-
-
- [Tab] Switch section | 1-5 jump | Esc up
-
-
-
{(section, index) => (
@@ -88,33 +56,22 @@ export function SettingsPage(props: SettingsScreenProps) {
- {activeSection() === "sync" && }
- {activeSection() === "sources" && }
- {activeSection() === "preferences" && }
- {activeSection() === "visualizer" && }
- {activeSection() === "account" && (
+ {activeSection() === SettingsPaneType.SYNC && }
+ {activeSection() === SettingsPaneType.SOURCES && (
+
+ )}
+ {activeSection() === SettingsPaneType.PREFERENCES && (
+
+ )}
+ {activeSection() === SettingsPaneType.VISUALIZER && (
+
+ )}
+ {activeSection() === SettingsPaneType.ACCOUNT && (
Account
-
- Status:
-
- {props.accountLabel}
-
-
- props.onOpenAccount?.()}>
- [A] Manage Account
-
)}
-
- Enter to dive | Esc up
);
}
diff --git a/src/types/navigation.ts b/src/types/navigation.ts
deleted file mode 100644
index 54ec36d..0000000
--- a/src/types/navigation.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export enum DIRECTION {
- Increment,
- Decrement,
-}
diff --git a/src/utils/navigation.ts b/src/utils/navigation.ts
index 3170706..36b06cd 100644
--- a/src/utils/navigation.ts
+++ b/src/utils/navigation.ts
@@ -1,9 +1,14 @@
-import { DiscoverPage } from "@/pages/Discover/DiscoverPage";
+import { DiscoverPage, DiscoverPaneCount } from "@/pages/Discover/DiscoverPage";
import { FeedPage, FeedPaneCount } from "@/pages/Feed/FeedPage";
import { MyShowsPage, MyShowsPaneCount } from "@/pages/MyShows/MyShowsPage";
-import { PlayerPage } from "@/pages/Player/PlayerPage";
-import { SearchPage } from "@/pages/Search/SearchPage";
-import { SettingsPage } from "@/pages/Settings/SettingsPage";
+import { PlayerPage, PlayerPaneCount } from "@/pages/Player/PlayerPage";
+import { SearchPage, SearchPaneCount } from "@/pages/Search/SearchPage";
+import { SettingsPage, SettingsPaneCount } from "@/pages/Settings/SettingsPage";
+
+export enum DIRECTION {
+ Increment,
+ Decrement,
+}
export enum TABS {
FEED,
@@ -28,5 +33,5 @@ export const LayerDepths = {
[TABS.DISCOVER]: DiscoverPaneCount,
[TABS.SEARCH]: SearchPaneCount,
[TABS.PLAYER]: PlayerPaneCount,
- [TABS.SETTINGS]: SettingPaneCount,
+ [TABS.SETTINGS]: SettingsPaneCount,
};