diff --git a/src/App.tsx b/src/App.tsx index 3d6f565..ba0cea6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ import { createSignal, createMemo, ErrorBoundary } from "solid-js"; import { useSelectionHandler } from "@opentui/solid"; import { Layout } from "./Layout"; -import { TabNavigation } from "./components/TabNavigation"; +import { TabId, TabNavigation } from "./components/TabNavigation"; import { FeedPage } from "@/tabs/Feed/FeedPage"; import { MyShowsPage } from "@/tabs/MyShows/MyShowsPage"; import { LoginScreen } from "@/tabs/Settings/LoginScreen"; @@ -21,7 +21,6 @@ import { useAppKeyboard } from "@/hooks/useAppKeyboard"; import { Clipboard } from "@/utils/clipboard"; import { useToast } from "@/ui/toast"; import { useRenderer } from "@opentui/solid"; -import type { TabId } from "@/components/Tab"; import type { AuthScreen } from "@/types/auth"; import type { Episode } from "@/types/episode"; diff --git a/src/Layout.tsx b/src/Layout.tsx index f012853..4a4890a 100644 --- a/src/Layout.tsx +++ b/src/Layout.tsx @@ -47,26 +47,13 @@ export function Layout(props: LayoutProps) { return ( - {/* Header - tab bar */} - - - - {props.header} - - - + {props.header} - {/* Main content: side-by-side panels */} {(panel, index) => ( diff --git a/src/components/CodeValidation.tsx b/src/components/CodeValidation.tsx index 2414070..757f0e7 100644 --- a/src/components/CodeValidation.tsx +++ b/src/components/CodeValidation.tsx @@ -72,7 +72,7 @@ export function CodeValidation(props: CodeValidationProps) { ? (currentIndex - 1 + fields.length) % fields.length : (currentIndex + 1) % fields.length; setFocusField(fields[nextIndex]); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return" || key.name === "tab") { if (focusField() === "submit") { handleSubmit(); } else if (focusField() === "back" && props.onBack) { diff --git a/src/components/TabNavigation.tsx b/src/components/TabNavigation.tsx index 8db6925..7a598c8 100644 --- a/src/components/TabNavigation.tsx +++ b/src/components/TabNavigation.tsx @@ -18,7 +18,14 @@ export const tabs: TabDefinition[] = [ export function TabNavigation(props: TabNavigationProps) { const { theme } = useTheme(); return ( - + {(tab) => ( props.onTabSelect(tab.id)} style={{ - padding: 1, - paddingLeft: 2, backgroundColor: tab.id == props.activeTab ? theme.primary : "transparent", }} > - - {tab.id == props.activeTab ? "[" : " "} + {tab.label} - {tab.id == props.activeTab ? "]" : " "} )} diff --git a/src/hooks/useAppKeyboard.ts b/src/hooks/useAppKeyboard.ts index b8f1451..e6965f2 100644 --- a/src/hooks/useAppKeyboard.ts +++ b/src/hooks/useAppKeyboard.ts @@ -4,11 +4,18 @@ */ import { useKeyboard, useRenderer } from "@opentui/solid" -import type { TabId } from "../components/Tab" import type { Accessor } from "solid-js" const TAB_ORDER: TabId[] = ["feed", "shows", "discover", "search", "player", "settings"] +type TabId = + | "feed" + | "shows" + | "discover" + | "search" + | "player" + | "settings" + type ShortcutOptions = { activeTab: TabId onTabChange: (tab: TabId) => void @@ -53,8 +60,9 @@ export function useAppKeyboard(options: ShortcutOptions) { return } + // Return key cycles tabs (equivalent to Tab) if (key.name === "return") { - options.onAction?.("enter") + options.onTabChange(getNextTab(options.activeTab)) return } diff --git a/src/hooks/useKeyboardShortcuts.ts b/src/hooks/useKeyboardShortcuts.ts deleted file mode 100644 index 558abce..0000000 --- a/src/hooks/useKeyboardShortcuts.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useKeyboard, useRenderer } from "@opentui/solid" - -type ShortcutOptions = { - onSave?: () => void - onQuit?: () => void - onTabNext?: () => void - onTabPrev?: () => void -} - -export function useKeyboardShortcuts(options: ShortcutOptions) { - const renderer = useRenderer() - - useKeyboard((key) => { - if (key.ctrl && key.name === "q") { - if (options.onQuit) { - options.onQuit() - } else { - renderer.destroy() - } - return - } - - if (key.ctrl && key.name === "s") { - options.onSave?.() - return - } - - if (key.name === "right") { - options.onTabNext?.() - return - } - - if (key.name === "left") { - options.onTabPrev?.() - } - }) -} diff --git a/src/tabs/Discover/DiscoverPage.tsx b/src/tabs/Discover/DiscoverPage.tsx index c9c7a17..36709ce 100644 --- a/src/tabs/Discover/DiscoverPage.tsx +++ b/src/tabs/Discover/DiscoverPage.tsx @@ -38,7 +38,7 @@ export function DiscoverPage(props: DiscoverPageProps) { } if ( - (key.name === "return" || key.name === "enter") && + key.name === "return" && area === "categories" ) { setFocusArea("shows"); diff --git a/src/tabs/Feed/FeedDetail.tsx b/src/tabs/Feed/FeedDetail.tsx index 39dc338..891bed6 100644 --- a/src/tabs/Feed/FeedDetail.tsx +++ b/src/tabs/Feed/FeedDetail.tsx @@ -57,7 +57,7 @@ export function FeedDetail(props: FeedDetailProps) { setSelectedIndex((i) => Math.max(0, i - 1)); } else if (key.name === "down" || key.name === "j") { setSelectedIndex((i) => Math.min(eps.length - 1, i + 1)); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return") { const episode = eps[selectedIndex()]; if (episode && props.onPlayEpisode) { props.onPlayEpisode(episode); diff --git a/src/tabs/Feed/FeedFilter.tsx b/src/tabs/Feed/FeedFilter.tsx index 835d2d1..666f455 100644 --- a/src/tabs/Feed/FeedFilter.tsx +++ b/src/tabs/Feed/FeedFilter.tsx @@ -30,7 +30,7 @@ export function FeedFilterComponent(props: FeedFilterProps) { ? (currentIndex - 1 + fields.length) % fields.length : (currentIndex + 1) % fields.length; setFocusField(fields[nextIndex]); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return") { if (focusField() === "visibility") { cycleVisibility(); } else if (focusField() === "sort") { diff --git a/src/tabs/Feed/FeedList.tsx b/src/tabs/Feed/FeedList.tsx index c454a08..8b6c3b5 100644 --- a/src/tabs/Feed/FeedList.tsx +++ b/src/tabs/Feed/FeedList.tsx @@ -37,7 +37,7 @@ export function FeedList(props: FeedListProps) { setSelectedIndex((i) => Math.max(0, i - 1)); } else if (key.name === "down" || key.name === "j") { setSelectedIndex((i) => Math.min(feeds.length - 1, i + 1)); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return") { const feed = feeds[selectedIndex()]; if (feed && props.onOpenFeed) { props.onOpenFeed(feed); diff --git a/src/tabs/Feed/FeedPage.tsx b/src/tabs/Feed/FeedPage.tsx index 79d71ba..a9a9291 100644 --- a/src/tabs/Feed/FeedPage.tsx +++ b/src/tabs/Feed/FeedPage.tsx @@ -50,7 +50,7 @@ export function FeedPage(props: FeedPageProps) { setSelectedIndex((i) => Math.min(episodes.length - 1, i + 1)); } else if (key.name === "up" || key.name === "k") { setSelectedIndex((i) => Math.max(0, i - 1)); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return") { const item = episodes[selectedIndex()]; if (item) props.onPlayEpisode?.(item.episode, item.feed); } else if (key.name === "home" || key.name === "g") { diff --git a/src/tabs/Search/SearchPage.tsx b/src/tabs/Search/SearchPage.tsx index efa89e9..eeeecd7 100644 --- a/src/tabs/Search/SearchPage.tsx +++ b/src/tabs/Search/SearchPage.tsx @@ -63,7 +63,7 @@ export function SearchPage(props: SearchPageProps) { const area = focusArea(); // Enter to search from input - if ((key.name === "return" || key.name === "enter") && area === "input") { + if (key.name === "return" && area === "input") { handleSearch(); return; } diff --git a/src/tabs/Settings/LoginScreen.tsx b/src/tabs/Settings/LoginScreen.tsx index 50b62de..01cbe1e 100644 --- a/src/tabs/Settings/LoginScreen.tsx +++ b/src/tabs/Settings/LoginScreen.tsx @@ -71,7 +71,7 @@ export function LoginScreen(props: LoginScreenProps) { ? (currentIndex - 1 + fields.length) % fields.length : (currentIndex + 1) % fields.length; setFocusField(fields[nextIndex]); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return") { if (focusField() === "submit") { handleSubmit(); } else if (focusField() === "code" && props.onNavigateToCode) { diff --git a/src/tabs/Settings/OAuthPlaceholder.tsx b/src/tabs/Settings/OAuthPlaceholder.tsx index 10f83ce..c1786ab 100644 --- a/src/tabs/Settings/OAuthPlaceholder.tsx +++ b/src/tabs/Settings/OAuthPlaceholder.tsx @@ -26,7 +26,7 @@ export function OAuthPlaceholder(props: OAuthPlaceholderProps) { ? (currentIndex - 1 + fields.length) % fields.length : (currentIndex + 1) % fields.length; setFocusField(fields[nextIndex]); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return") { if (focusField() === "code" && props.onNavigateToCode) { props.onNavigateToCode(); } else if (focusField() === "back" && props.onBack) { diff --git a/src/tabs/Settings/PreferencesPanel.tsx b/src/tabs/Settings/PreferencesPanel.tsx index fe1b15e..fd659b5 100644 --- a/src/tabs/Settings/PreferencesPanel.tsx +++ b/src/tabs/Settings/PreferencesPanel.tsx @@ -46,7 +46,7 @@ export function PreferencesPanel() { if (key.name === "right" || key.name === "l") { stepValue(1); } - if (key.name === "space" || key.name === "return" || key.name === "enter") { + if (key.name === "space" || key.name === "return") { toggleValue(); } }; diff --git a/src/tabs/Settings/SourceManager.tsx b/src/tabs/Settings/SourceManager.tsx index 818c71d..749d68e 100644 --- a/src/tabs/Settings/SourceManager.tsx +++ b/src/tabs/Settings/SourceManager.tsx @@ -62,7 +62,6 @@ export function SourceManager(props: SourceManagerProps) { setSelectedIndex((i) => Math.min(sources().length - 1, i + 1)); } else if ( key.name === "return" || - key.name === "enter" || key.name === "space" ) { const source = sources()[selectedIndex()]; @@ -98,7 +97,6 @@ export function SourceManager(props: SourceManagerProps) { if (focusArea() === "explicit") { if ( - key.name === "enter" || key.name === "return" || key.name === "space" ) { @@ -113,7 +111,6 @@ export function SourceManager(props: SourceManagerProps) { if (focusArea() === "language") { if ( - key.name === "enter" || key.name === "return" || key.name === "space" ) { diff --git a/src/tabs/Settings/SyncProfile.tsx b/src/tabs/Settings/SyncProfile.tsx index eb05f11..648ca5f 100644 --- a/src/tabs/Settings/SyncProfile.tsx +++ b/src/tabs/Settings/SyncProfile.tsx @@ -29,7 +29,7 @@ export function SyncProfile(props: SyncProfileProps) { ? (currentIndex - 1 + fields.length) % fields.length : (currentIndex + 1) % fields.length; setFocusField(fields[nextIndex]); - } else if (key.name === "return" || key.name === "enter") { + } else if (key.name === "return") { if (focusField() === "sync" && props.onManageSync) { props.onManageSync(); } else if (focusField() === "logout" && props.onLogout) {