Compare commits

..

4 Commits

Author SHA1 Message Date
1618588a30 cycle 2026-02-22 19:07:07 -05:00
c9a370a424 more keyboard handling 2026-02-21 00:46:36 -05:00
b45e7bf538 temp keyboard handling 2026-02-20 23:42:29 -05:00
1e6618211a more indication 2026-02-20 22:42:15 -05:00
8 changed files with 401 additions and 144 deletions

View File

@@ -18,8 +18,9 @@ export type KeybindsResolved = {
inverseModifier: string; inverseModifier: string;
leader: string; // will not trigger while focused on input leader: string; // will not trigger while focused on input
quit: string[]; quit: string[];
select: string[]; // for selecting/activating items
"audio-toggle": string[]; "audio-toggle": string[];
"audio-pause": []; "audio-pause": string[];
"audio-play": string[]; "audio-play": string[];
"audio-next": string[]; "audio-next": string[];
"audio-prev": string[]; "audio-prev": string[];
@@ -36,6 +37,7 @@ export enum KeybindAction {
DIVE, DIVE,
OUT, OUT,
QUIT, QUIT,
SELECT,
AUDIO_TOGGLE, AUDIO_TOGGLE,
AUDIO_PAUSE, AUDIO_PAUSE,
AUDIO_PLAY, AUDIO_PLAY,
@@ -60,6 +62,7 @@ export const { use: useKeybinds, provider: KeybindProvider } =
inverseModifier: "", inverseModifier: "",
leader: "", leader: "",
quit: [], quit: [],
select: [],
refresh: [], refresh: [],
"audio-toggle": [], "audio-toggle": [],
"audio-pause": [], "audio-pause": [],

View File

@@ -2,13 +2,14 @@
* DiscoverPage component - Main discover/browse interface for PodTUI * DiscoverPage component - Main discover/browse interface for PodTUI
*/ */
import { createSignal, For, Show } from "solid-js"; import { createSignal, For, Show, onMount } from "solid-js";
import { useKeyboard } from "@opentui/solid"; import { useKeyboard } from "@opentui/solid";
import { useDiscoverStore, DISCOVER_CATEGORIES } from "@/stores/discover"; import { useDiscoverStore, DISCOVER_CATEGORIES } from "@/stores/discover";
import { useTheme } from "@/context/ThemeContext"; import { useTheme } from "@/context/ThemeContext";
import { PodcastCard } from "./PodcastCard"; import { PodcastCard } from "./PodcastCard";
import { SelectableBox, SelectableText } from "@/components/Selectable"; import { SelectableBox, SelectableText } from "@/components/Selectable";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum DiscoverPagePaneType { enum DiscoverPagePaneType {
CATEGORIES = 1, CATEGORIES = 1,
@@ -21,6 +22,38 @@ export function DiscoverPage() {
const [showIndex, setShowIndex] = createSignal(0); const [showIndex, setShowIndex] = createSignal(0);
const [categoryIndex, setCategoryIndex] = createSignal(0); const [categoryIndex, setCategoryIndex] = createSignal(0);
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
onMount(() => {
useKeyboard(
(keyEvent: any) => {
const isDown = keybind.match("down", keyEvent);
const isUp = keybind.match("up", keyEvent);
const isCycle = keybind.match("cycle", keyEvent);
const isSelect = keybind.match("select", keyEvent);
if (isSelect) {
const filteredPodcasts = discoverStore.filteredPodcasts();
if (filteredPodcasts.length > 0 && showIndex() < filteredPodcasts.length) {
setShowIndex(showIndex() + 1);
}
return;
}
const filteredPodcasts = discoverStore.filteredPodcasts();
if (filteredPodcasts.length === 0) return;
if (isDown) {
setShowIndex((i) => (i + 1) % filteredPodcasts.length);
} else if (isUp) {
setShowIndex((i) => (i - 1 + filteredPodcasts.length) % filteredPodcasts.length);
} else if (isCycle) {
setShowIndex((i) => (i + 1) % filteredPodcasts.length);
}
},
{ release: false },
);
});
const handleCategorySelect = (categoryId: string) => { const handleCategorySelect = (categoryId: string) => {
discoverStore.setSelectedCategory(categoryId); discoverStore.setSelectedCategory(categoryId);
@@ -43,13 +76,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
} }
@@ -80,12 +117,16 @@ export function DiscoverPage() {
flexDirection="column" flexDirection="column"
flexGrow={1} flexGrow={1}
border border
borderColor={theme.border} borderColor={
nav.activeDepth() == DiscoverPagePaneType.SHOWS
? theme.accent
: theme.border
}
> >
<box padding={1}> <box padding={1}>
<SelectableText <SelectableText
selected={() => false} selected={() => false}
primary={nav.activeDepth == DiscoverPagePaneType.SHOWS} primary={nav.activeDepth() == DiscoverPagePaneType.SHOWS}
> >
Trending in{" "} Trending in{" "}
{DISCOVER_CATEGORIES.find( {DISCOVER_CATEGORIES.find(
@@ -111,7 +152,9 @@ export function DiscoverPage() {
discoverStore.filteredPodcasts().length === 0 discoverStore.filteredPodcasts().length === 0
} }
> >
<scrollbox> <scrollbox
focused={nav.activeDepth() == DiscoverPagePaneType.SHOWS}
>
<box flexDirection="column"> <box flexDirection="column">
<For each={discoverStore.filteredPodcasts()}> <For each={discoverStore.filteredPodcasts()}>
{(podcast, index) => ( {(podcast, index) => (
@@ -119,7 +162,7 @@ export function DiscoverPage() {
podcast={podcast} podcast={podcast}
selected={ selected={
index() === showIndex() && index() === showIndex() &&
nav.activeDepth == DiscoverPagePaneType.SHOWS nav.activeDepth() == DiscoverPagePaneType.SHOWS
} }
onSelect={() => handleShowSelect(index())} onSelect={() => handleShowSelect(index())}
onSubscribe={() => handleSubscribe(podcast)} onSubscribe={() => handleSubscribe(podcast)}

View File

@@ -3,7 +3,7 @@
* Reverse chronological order, grouped by date * Reverse chronological order, grouped by date
*/ */
import { createSignal, For, Show } from "solid-js"; import { createSignal, For, Show, onMount } from "solid-js";
import { useFeedStore } from "@/stores/feed"; import { useFeedStore } from "@/stores/feed";
import { format } from "date-fns"; import { format } from "date-fns";
import type { Episode } from "@/types/episode"; import type { Episode } from "@/types/episode";
@@ -13,6 +13,8 @@ import { SelectableBox, SelectableText } from "@/components/Selectable";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { LoadingIndicator } from "@/components/LoadingIndicator"; import { LoadingIndicator } from "@/components/LoadingIndicator";
import { TABS } from "@/utils/navigation"; import { TABS } from "@/utils/navigation";
import { useKeyboard } from "@opentui/solid";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum FeedPaneType { enum FeedPaneType {
FEED = 1, FEED = 1,
@@ -29,6 +31,39 @@ export function FeedPage() {
string | undefined string | undefined
>(); >();
const allEpisodes = () => feedStore.getAllEpisodesChronological(); const allEpisodes = () => feedStore.getAllEpisodesChronological();
const keybind = useKeybinds();
const [focusedIndex, setFocusedIndex] = createSignal(0);
onMount(() => {
useKeyboard(
(keyEvent: any) => {
const isDown = keybind.match("down", keyEvent);
const isUp = keybind.match("up", keyEvent);
const isCycle = keybind.match("cycle", keyEvent);
const isSelect = keybind.match("select", keyEvent);
if (isSelect) {
const episodes = allEpisodes();
if (episodes.length > 0 && episodes[focusedIndex()]) {
setSelectedEpisodeID(episodes[focusedIndex()].episode.id);
}
return;
}
const episodes = allEpisodes();
if (episodes.length === 0) return;
if (isDown) {
setFocusedIndex((i) => (i + 1) % episodes.length);
} else if (isUp) {
setFocusedIndex((i) => (i - 1 + episodes.length) % episodes.length);
} else if (isCycle) {
setFocusedIndex((i) => (i + 1) % episodes.length);
}
},
{ release: false },
);
});
const formatDate = (date: Date): string => { const formatDate = (date: Date): string => {
return format(date, "MMM d, yyyy"); return format(date, "MMM d, yyyy");
@@ -105,6 +140,13 @@ export function FeedPage() {
} }
return false; return false;
}; };
const isFocused = () => {
const episodes = allEpisodes();
const currentIndex = episodes.findIndex(
(e: any) => e.episode.id === item.episode.id,
);
return currentIndex === focusedIndex();
};
return ( return (
<SelectableBox <SelectableBox
selected={isSelected} selected={isSelected}
@@ -115,7 +157,11 @@ export function FeedPage() {
paddingTop={0} paddingTop={0}
paddingBottom={0} paddingBottom={0}
onMouseDown={() => { onMouseDown={() => {
// Selection is handled by App's keyboard navigation setSelectedEpisodeID(item.episode.id);
const episodes = allEpisodes();
setFocusedIndex(
episodes.findIndex((e: any) => e.episode.id === item.episode.id),
);
}} }}
> >
<SelectableText selected={isSelected} primary> <SelectableText selected={isSelected} primary>

View File

@@ -4,7 +4,8 @@
* Right panel: episodes for the selected show * Right panel: episodes for the selected show
*/ */
import { createSignal, For, Show, createMemo, createEffect } from "solid-js"; import { createSignal, For, Show, createMemo, createEffect, onMount } from "solid-js";
import { useKeyboard } from "@opentui/solid";
import { useFeedStore } from "@/stores/feed"; import { useFeedStore } from "@/stores/feed";
import { useDownloadStore } from "@/stores/download"; import { useDownloadStore } from "@/stores/download";
import { DownloadStatus } from "@/types/episode"; import { DownloadStatus } from "@/types/episode";
@@ -13,6 +14,7 @@ import { useTheme } from "@/context/ThemeContext";
import { useAudioNavStore, AudioSource } from "@/stores/audio-nav"; import { useAudioNavStore, AudioSource } from "@/stores/audio-nav";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { LoadingIndicator } from "@/components/LoadingIndicator"; import { LoadingIndicator } from "@/components/LoadingIndicator";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum MyShowsPaneType { enum MyShowsPaneType {
SHOWS = 1, SHOWS = 1,
@@ -31,6 +33,53 @@ export function MyShowsPage() {
const { theme } = useTheme(); const { theme } = useTheme();
const mutedColor = () => theme.muted || theme.text; const mutedColor = () => theme.muted || theme.text;
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
onMount(() => {
useKeyboard(
(keyEvent: any) => {
const isDown = keybind.match("down", keyEvent);
const isUp = keybind.match("up", keyEvent);
const isCycle = keybind.match("cycle", keyEvent);
const isSelect = keybind.match("select", keyEvent);
const shows = feedStore.getFilteredFeeds();
const episodesList = episodes();
const selected = selectedShow();
if (isSelect) {
if (shows.length > 0 && showIndex() < shows.length) {
setShowIndex(showIndex() + 1);
}
if (episodesList.length > 0 && episodeIndex() < episodesList.length) {
setEpisodeIndex(episodeIndex() + 1);
}
return;
}
if (shows.length > 0) {
if (isDown) {
setShowIndex((i) => (i + 1) % shows.length);
} else if (isUp) {
setShowIndex((i) => (i - 1 + shows.length) % shows.length);
} else if (isCycle) {
setShowIndex((i) => (i + 1) % shows.length);
}
}
if (episodesList.length > 0) {
if (isDown) {
setEpisodeIndex((i) => (i + 1) % episodesList.length);
} else if (isUp) {
setEpisodeIndex((i) => (i - 1 + episodesList.length) % episodesList.length);
} else if (isCycle) {
setEpisodeIndex((i) => (i + 1) % episodesList.length);
}
}
},
{ release: false },
);
});
/** Threshold: load more when within this many items of the end */ /** Threshold: load more when within this many items of the end */
const LOAD_MORE_THRESHOLD = 5; const LOAD_MORE_THRESHOLD = 5;
@@ -129,8 +178,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) => (
@@ -188,8 +243,14 @@ export function MyShowsPage() {
} }
> >
<scrollbox <scrollbox
border
height="100%" height="100%"
focused={nav.activeDepth == MyShowsPaneType.EPISODES} borderColor={
nav.activeDepth() == MyShowsPaneType.EPISODES
? theme.accent
: theme.border
}
focused={nav.activeDepth() == MyShowsPaneType.EPISODES}
> >
<For each={episodes()}> <For each={episodes()}>
{(episode, index) => ( {(episode, index) => (

View File

@@ -3,6 +3,10 @@ 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";
import { useKeybinds } from "@/context/KeybindContext";
import { useKeyboard } from "@opentui/solid";
import { onMount } from "solid-js";
enum PlayerPaneType { enum PlayerPaneType {
PLAYER = 1, PLAYER = 1,
@@ -12,6 +16,31 @@ 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 keybind = useKeybinds();
onMount(() => {
useKeyboard(
(keyEvent: any) => {
if (keybind.match("audio-toggle", keyEvent)) {
audio.togglePlayback();
return;
}
if (keybind.match("audio-seek-forward", keyEvent)) {
audio.seek(audio.currentEpisode()?.duration ?? 0);
return;
}
if (keybind.match("audio-seek-backward", keyEvent)) {
audio.seek(0);
return;
}
},
{ release: false },
);
});
const progressPercent = () => { const progressPercent = () => {
const d = audio.duration(); const d = audio.duration();
@@ -41,7 +70,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}

View File

@@ -2,7 +2,7 @@
* SearchPage component - Main search interface for PodTUI * SearchPage component - Main search interface for PodTUI
*/ */
import { createSignal, createEffect, Show } from "solid-js"; import { createSignal, createEffect, Show, onMount } from "solid-js";
import { useKeyboard } from "@opentui/solid"; import { useKeyboard } from "@opentui/solid";
import { useSearchStore } from "@/stores/search"; import { useSearchStore } from "@/stores/search";
import { SearchResults } from "./SearchResults"; import { SearchResults } from "./SearchResults";
@@ -11,6 +11,7 @@ import type { SearchResult } from "@/types/source";
import { MyShowsPage } from "../MyShows/MyShowsPage"; import { MyShowsPage } from "../MyShows/MyShowsPage";
import { useTheme } from "@/context/ThemeContext"; import { useTheme } from "@/context/ThemeContext";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum SearchPaneType { enum SearchPaneType {
INPUT = 1, INPUT = 1,
@@ -26,6 +27,38 @@ export function SearchPage() {
const [historyIndex, setHistoryIndex] = createSignal(0); const [historyIndex, setHistoryIndex] = createSignal(0);
const { theme } = useTheme(); const { theme } = useTheme();
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
onMount(() => {
useKeyboard(
(keyEvent: any) => {
const isDown = keybind.match("down", keyEvent);
const isUp = keybind.match("up", keyEvent);
const isCycle = keybind.match("cycle", keyEvent);
const isSelect = keybind.match("select", keyEvent);
if (isSelect) {
const results = searchStore.results();
if (results.length > 0 && resultIndex() < results.length) {
setResultIndex(resultIndex() + 1);
}
return;
}
const results = searchStore.results();
if (results.length === 0) return;
if (isDown) {
setResultIndex((i) => (i + 1) % results.length);
} else if (isUp) {
setResultIndex((i) => (i - 1 + results.length) % results.length);
} else if (isCycle) {
setResultIndex((i) => (i + 1) % results.length);
}
},
{ release: false },
);
});
const handleSearch = async () => { const handleSearch = async () => {
const query = inputValue().trim(); const query = inputValue().trim();
@@ -69,7 +102,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
@@ -99,12 +132,16 @@ export function SearchPage() {
flexDirection="column" flexDirection="column"
flexGrow={1} flexGrow={1}
border border
borderColor={theme.border} borderColor={
nav.activeDepth() === SearchPaneType.RESULTS
? theme.accent
: theme.border
}
> >
<box padding={1}> <box padding={1}>
<text <text
fg={ fg={
nav.activeDepth === SearchPaneType.RESULTS nav.activeDepth() === SearchPaneType.RESULTS
? theme.primary ? theme.primary
: theme.muted : theme.muted
} }
@@ -127,7 +164,7 @@ export function SearchPage() {
<SearchResults <SearchResults
results={searchStore.results()} results={searchStore.results()}
selectedIndex={resultIndex()} selectedIndex={resultIndex()}
focused={nav.activeDepth === SearchPaneType.RESULTS} focused={nav.activeDepth() === SearchPaneType.RESULTS}
onSelect={handleResultSelect} onSelect={handleResultSelect}
onChange={setResultIndex} onChange={setResultIndex}
isSearching={searchStore.isSearching()} isSearching={searchStore.isSearching()}
@@ -142,7 +179,7 @@ export function SearchPage() {
<box paddingBottom={1}> <box paddingBottom={1}>
<text <text
fg={ fg={
nav.activeDepth === SearchPaneType.HISTORY nav.activeDepth() === SearchPaneType.HISTORY
? theme.primary ? theme.primary
: theme.muted : theme.muted
} }
@@ -153,7 +190,7 @@ export function SearchPage() {
<SearchHistory <SearchHistory
history={searchStore.history()} history={searchStore.history()}
selectedIndex={historyIndex()} selectedIndex={historyIndex()}
focused={nav.activeDepth === SearchPaneType.HISTORY} focused={nav.activeDepth() === SearchPaneType.HISTORY}
onSelect={handleHistorySelect} onSelect={handleHistorySelect}
onRemove={searchStore.removeFromHistory} onRemove={searchStore.removeFromHistory}
onClear={searchStore.clearHistory} onClear={searchStore.clearHistory}

View File

@@ -1,4 +1,4 @@
import { createSignal, For } from "solid-js"; import { createSignal, For, onMount } from "solid-js";
import { useKeyboard } from "@opentui/solid"; import { useKeyboard } from "@opentui/solid";
import { SourceManager } from "./SourceManager"; import { SourceManager } from "./SourceManager";
import { useTheme } from "@/context/ThemeContext"; import { useTheme } from "@/context/ThemeContext";
@@ -6,6 +6,7 @@ import { PreferencesPanel } from "./PreferencesPanel";
import { SyncPanel } from "./SyncPanel"; import { SyncPanel } from "./SyncPanel";
import { VisualizerSettings } from "./VisualizerSettings"; import { VisualizerSettings } from "./VisualizerSettings";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum SettingsPaneType { enum SettingsPaneType {
SYNC = 1, SYNC = 1,
@@ -27,6 +28,42 @@ const SECTIONS: Array<{ id: SettingsPaneType; label: string }> = [
export function SettingsPage() { export function SettingsPage() {
const { theme } = useTheme(); const { theme } = useTheme();
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
// Helper function to check if a depth is active
const isActive = (depth: SettingsPaneType): boolean => {
return nav.activeDepth() === depth;
};
// Helper function to get the current depth as a number
const currentDepth = () => nav.activeDepth() as number;
onMount(() => {
useKeyboard(
(keyEvent: any) => {
const isDown = keybind.match("down", keyEvent);
const isUp = keybind.match("up", keyEvent);
const isCycle = keybind.match("cycle", keyEvent);
const isSelect = keybind.match("select", keyEvent);
if (isSelect) {
nav.setActiveDepth((nav.activeDepth() % SettingsPaneCount) + 1);
return;
}
const nextDepth = isDown
? (nav.activeDepth() % SettingsPaneCount) + 1
: (nav.activeDepth() - 2 + SettingsPaneCount) % SettingsPaneCount + 1;
if (isCycle) {
nav.setActiveDepth((nav.activeDepth() % SettingsPaneCount) + 1);
} else {
nav.setActiveDepth(nextDepth);
}
},
{ release: false },
);
});
return ( return (
<box flexDirection="column" gap={1} height="100%" width="100%"> <box flexDirection="column" gap={1} height="100%" width="100%">
@@ -38,13 +75,13 @@ export function SettingsPage() {
borderColor={theme.border} borderColor={theme.border}
padding={0} padding={0}
backgroundColor={ backgroundColor={
nav.activeDepth === section.id ? theme.primary : undefined currentDepth() === section.id ? theme.primary : undefined
} }
onMouseDown={() => nav.setActiveDepth(section.id)} onMouseDown={() => nav.setActiveDepth(section.id)}
> >
<text <text
fg={ fg={
nav.activeDepth === section.id ? theme.text : theme.textMuted currentDepth() === section.id ? theme.text : theme.textMuted
} }
> >
[{index() + 1}] {section.label} [{index() + 1}] {section.label}
@@ -56,23 +93,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>

View File

@@ -27,6 +27,7 @@ const DEFAULT_KEYBINDS: KeybindsResolved = {
right: ["right", "l"], right: ["right", "l"],
cycle: ["tab"], cycle: ["tab"],
dive: ["return"], dive: ["return"],
select: ["return"],
out: ["esc"], out: ["esc"],
inverseModifier: "shift", inverseModifier: "shift",
leader: ":", leader: ":",